[kernel/f15] rebase to 3.1.0

Dave Jones davej at fedoraproject.org
Mon Nov 7 19:59:21 UTC 2011


commit 1f93f04e2352a8390a591837af111fcaa8619e31
Author: Dave Jones <davej at redhat.com>
Date:   Mon Nov 7 14:52:27 2011 -0500

    rebase to 3.1.0

 .gitignore                                         |    5 +-
 Makefile                                           |   18 +-
 Makefile.config                                    |   29 +-
 TEGRA-2.6.40.2-enable-USB-ports.patch              |  111 -
 acpi-ec-add-delay-before-write.patch               |   51 -
 add-appleir-usb-driver.patch                       |    5 +-
 add-macbookair41-keyboard.patch                    |  119 +
 arm-omap-dt-compat.patch                           |    4 +-
 be2net-move-to-new-vlan-model.patch                |  107 -
 config-arm-generic                                 |    7 +-
 config-arm-omap-generic                            |   12 +-
 config-arm-tegra                                   |    6 +-
 config-debug                                       |    9 +-
 config-generic                                     |  207 +-
 config-ia64-generic                                |  213 -
 config-nodebug                                     |    9 +-
 config-powerpc-generic                             |   15 +
 config-powerpc64                                   |   23 +-
 config-s390x                                       |    1 -
 config-sparc64-generic                             |    2 -
 config-x86-32-generic                              |  206 +
 config-x86-generic                                 |  304 +-
 config-x86_64-generic                              |  387 +-
 dmar-disable-when-ricoh-multifunction.patch        |    4 +-
 drm-i915-fbc-stfu.patch                            |  102 +
 drm-nouveau-updates.patch                          | 8870 +++++++++++++++++++-
 efi-dont-map-boot-services-on-32bit.patch          |   22 +
 epoll-fix-spurious-lockdep-warnings.patch          |    2 +-
 hda_intel-prealloc-4mb-dmabuffer.patch             |   47 -
 hvcs_pi_buf_alloc.patch                            |   43 +
 ...ad-Check-if-acpi-already-handle-backlight.patch |   31 +
 ...gn-fix-ht_params-NULL-pointer-dereference.patch |   43 +
 kernel.spec                                        |  197 +-
 linux-2.6-crash-driver.patch                       |   61 +-
 linux-2.6-debug-vm-would-have-oomkilled.patch      |   69 -
 linux-2.6-intel-iommu-igfx.patch                   |    4 +-
 linux-2.6-silence-noise.patch                      |    4 +-
 linux-2.6.29-sparc-IOC_TYPECHECK.patch             |   21 -
 linux-2.6.30-no-pcspkr-modalias.patch              |   13 +-
 media-DiBcom-protect-the-I2C-bufer-access.patch    |   27 +-
 media-dib0700-correct-error-message.patch          |   14 +-
 ...dib0700-protect-the-dib0700-buffer-access.patch |   14 +-
 perf-check-ownership.patch                         |   62 -
 powerpc-Fix-deadlock-in-icswx-code.patch           |   74 +
 rcu-avoid-just-onlined-cpu-resched.patch           |   47 +
 revert-efi-rtclock.patch                           |   76 +
 scripts/grab-logs.sh                               |    2 +-
 sources                                            |    3 +-
 taint-vbox.patch                                   |   15 +
 udlfb-bind-framebuffer-to-interface.patch          |   33 +
 ums-realtek-driver-uses-stack-memory-for-DMA.patch |   89 +-
 utrace.patch                                       | 3162 +++++---
 ...ix-automount-for-negative-autofs-dentries.patch |   56 -
 ...tack-from-regs-when-possible-in-dump_trac.patch |   86 -
 ...e-stack-pointer-in-perf-live-regs-savings.patch |   38 -
 x86-p4-make-watchdog-and-perf-work-together.patch  |  267 -
 ...y-of-host-bridge-window-conflict-warnings.patch |   40 -
 ...ossible-memory-corruption-in-xfs_readlink.patch |   50 +-
 58 files changed, 11780 insertions(+), 3758 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 03eb9bf..2a45958 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,4 @@ linux-*.tar.bz2
 patch-*.bz2
 clog
 *.rpm
-kernel-2.6.*/
-kernel-3.*/
-/patch-3.0.2-rc1.gz
-/patch-3.0.3-rc1.gz
+kernel-[23].*/
diff --git a/Makefile b/Makefile
index cffc926..3e9e3a8 100644
--- a/Makefile
+++ b/Makefile
@@ -36,13 +36,11 @@ debug:
 	@perl -pi -e 's/# CONFIG_DEBUG_SLAB is not set/CONFIG_DEBUG_SLAB=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_DEBUG_MUTEXES is not set/CONFIG_DEBUG_MUTEXES=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_DEBUG_RT_MUTEXES is not set/CONFIG_DEBUG_RT_MUTEXES=y/' config-nodebug
-	@perl -pi -e 's/# CONFIG_DEBUG_RWSEMS is not set/CONFIG_DEBUG_RWSEMS=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_DEBUG_LOCK_ALLOC is not set/CONFIG_DEBUG_LOCK_ALLOC=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_PROVE_LOCKING is not set/CONFIG_PROVE_LOCKING=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_PROVE_RCU is not set/CONFIG_PROVE_RCU=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_DEBUG_SPINLOCK is not set/CONFIG_DEBUG_SPINLOCK=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_DEBUG_VM is not set/CONFIG_DEBUG_VM=y/' config-nodebug
-	@perl -pi -e 's/# CONFIG_DEBUG_SLEEP_IN_IRQ is not set/CONFIG_DEBUG_SLEEP_IN_IRQ=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_FAULT_INJECTION is not set/CONFIG_FAULT_INJECTION=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_FAILSLAB is not set/CONFIG_FAILSLAB=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_FAIL_PAGE_ALLOC is not set/CONFIG_FAIL_PAGE_ALLOC=y/' config-nodebug
@@ -66,7 +64,6 @@ debug:
 	@perl -pi -e 's/# CONFIG_DMA_API_DEBUG is not set/CONFIG_DMA_API_DEBUG=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_PM_TEST_SUSPEND is not set/CONFIG_PM_TEST_SUSPEND=y/' config-generic
 	@perl -pi -e 's/# CONFIG_PM_ADVANCED_DEBUG is not set/CONFIG_PM_ADVANCED_DEBUG=y/' config-generic
-	@perl -pi -e 's/# CONFIG_BOOT_TRACER is not set/CONFIG_BOOT_TRACER=y/' config-generic
 	@perl -pi -e 's/# CONFIG_B43_DEBUG is not set/CONFIG_B43_DEBUG=y/' config-generic
 	@perl -pi -e 's/# CONFIG_B43LEGACY_DEBUG is not set/CONFIG_B43LEGACY_DEBUG=y/' config-generic
 	@perl -pi -e 's/# CONFIG_MMIOTRACE is not set/CONFIG_MMIOTRACE=y/' config-nodebug
@@ -77,7 +74,7 @@ debug:
 	@perl -pi -e 's/# CONFIG_EXT4_DEBUG is not set/CONFIG_EXT4_DEBUG=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_DEBUG_PERF_USE_VMALLOC is not set/CONFIG_DEBUG_PERF_USE_VMALLOC=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_JBD2_DEBUG is not set/CONFIG_JBD2_DEBUG=y/' config-nodebug
-	@perl -pi -e 's/# CONFIG_DEBUG_CFQ_IOSCHED is not set/CONFIG_DEBUG_CFQ_IOSCHED=y/' config-nodebug
+	@perl -pi -e 's/# CONFIG_DEBUG_BLK_CGROUP is not set/CONFIG_DEBUG_BLK_CGROUP=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_DRBD_FAULT_INJECTION is not set/CONFIG_DRBD_FAULT_INJECTION=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_ATH_DEBUG is not set/CONFIG_ATH_DEBUG=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_CARL9170_DEBUGFS is not set/CONFIG_CARL9170_DEBUGFS=y/' config-nodebug
@@ -92,6 +89,8 @@ debug:
 	@perl -pi -e 's/# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set/CONFIG_CPU_NOTIFIER_ERROR_INJECT=m/' config-nodebug
 	@perl -pi -e 's/# CONFIG_DEBUG_PER_CPU_MAPS is not set/CONFIG_DEBUG_PER_CPU_MAPS=y/' config-nodebug
 	@perl -pi -e 's/# CONFIG_TEST_LIST_SORT is not set/CONFIG_TEST_LIST_SORT=y/' config-nodebug
+	@perl -pi -e 's/# CONFIG_DEBUG_ATOMIC_SLEEP is not set/CONFIG_DEBUG_ATOMIC_SLEEP=y/' config-nodebug
+	@perl -pi -e 's/# CONFIG_DETECT_HUNG_TASK is not set/CONFIG_DETECT_HUNG_TASK=y/' config-nodebug
 
 	@perl -pi -e 's/# CONFIG_DEBUG_SET_MODULE_RONX is not set/CONFIG_DEBUG_SET_MODULE_RONX=y/' config-nodebug
 
@@ -114,13 +113,11 @@ release:
 	@perl -pi -e 's/CONFIG_DEBUG_SLAB=y/# CONFIG_DEBUG_SLAB is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_DEBUG_MUTEXES=y/# CONFIG_DEBUG_MUTEXES is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_DEBUG_RT_MUTEXES=y/# CONFIG_DEBUG_RT_MUTEXES is not set/' config-nodebug
-	@perl -pi -e 's/CONFIG_DEBUG_RWSEMS=y/# CONFIG_DEBUG_RWSEMS is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_DEBUG_LOCK_ALLOC=y/# CONFIG_DEBUG_LOCK_ALLOC is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_PROVE_LOCKING=y/# CONFIG_PROVE_LOCKING is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_PROVE_RCU=y/# CONFIG_PROVE_RCU is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_DEBUG_SPINLOCK=y/# CONFIG_DEBUG_SPINLOCK is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_DEBUG_VM=y/# CONFIG_DEBUG_VM is not set/' config-nodebug
-	@perl -pi -e 's/CONFIG_DEBUG_SLEEP_IN_IRQ=y/# CONFIG_DEBUG_SLEEP_IN_IRQ is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_FAULT_INJECTION=y/# CONFIG_FAULT_INJECTION is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_FAILSLAB=y/# CONFIG_FAILSLAB is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_FAIL_PAGE_ALLOC=y/# CONFIG_FAIL_PAGE_ALLOC is not set/' config-nodebug
@@ -142,9 +139,8 @@ release:
 	@perl -pi -e 's/CONFIG_SYSCTL_SYSCALL_CHECK=y/# CONFIG_SYSCTL_SYSCALL_CHECK is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_DEBUG_NOTIFIERS=y/# CONFIG_DEBUG_NOTIFIERS is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_DMA_API_DEBUG=y/# CONFIG_DMA_API_DEBUG is not set/' config-nodebug
-	@perl -pi -e 's/CONFIG_PM_TEST_SUSPEND=y/#\ CONFIG_PM_TEST_SUSPEND\ is\ not\ set/' config-generic
-	@perl -pi -e 's/CONFIG_PM_ADVANCED_DEBUG=y/#\ CONFIG_PM_ADVANCED_DEBUG\ is\ not\ set/' config-generic
-	@perl -pi -e 's/CONFIG_BOOT_TRACER=y/#\ CONFIG_BOOT_TRACER\ is\ not\ set/' config-generic
+	@perl -pi -e 's/CONFIG_PM_TEST_SUSPEND=y/# CONFIG_PM_TEST_SUSPEND is not set/' config-generic
+	@perl -pi -e 's/CONFIG_PM_ADVANCED_DEBUG=y/# CONFIG_PM_ADVANCED_DEBUG is not set/' config-generic
 	@perl -pi -e 's/CONFIG_B43_DEBUG=y/# CONFIG_B43_DEBUG is not set/' config-generic
 	@perl -pi -e 's/CONFIG_B43LEGACY_DEBUG=y/# CONFIG_B43LEGACY_DEBUG is not set/' config-generic
 	@perl -pi -e 's/CONFIG_MMIOTRACE=y/# CONFIG_MMIOTRACE is not set/' config-nodebug
@@ -155,7 +151,7 @@ release:
 	@perl -pi -e 's/CONFIG_EXT4_DEBUG=y/# CONFIG_EXT4_DEBUG is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_DEBUG_PERF_USE_VMALLOC=y/# CONFIG_DEBUG_PERF_USE_VMALLOC is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_JBD2_DEBUG=y/# CONFIG_JBD2_DEBUG is not set/' config-nodebug
-	@perl -pi -e 's/CONFIG_DEBUG_CFQ_IOSCHED=y/# CONFIG_DEBUG_CFQ_IOSCHED is not set/' config-nodebug
+	@perl -pi -e 's/CONFIG_DEBUG_BLK_CGROUP=y/# CONFIG_DEBUG_BLK_CGROUP is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_DRBD_FAULT_INJECTION=y/# CONFIG_DRBD_FAULT_INJECTION is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_ATH_DEBUG=y/# CONFIG_ATH_DEBUG is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_CARL9170_DEBUGFS=y/# CONFIG_CARL9170_DEBUGFS is not set/' config-nodebug
@@ -170,6 +166,8 @@ release:
 	#@perl -pi -e 's/CONFIG_KDB_KEYBOARD=y/# CONFIG_KDB_KEYBOARD is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_DEBUG_PER_CPU_MAPS=y/# CONFIG_DEBUG_PER_CPU_MAPS is not set/' config-nodebug
 	@perl -pi -e 's/CONFIG_TEST_LIST_SORT=y/# CONFIG_TEST_LIST_SORT is not set/' config-nodebug
+	@perl -pi -e 's/CONFIG_DEBUG_ATOMIC_SLEEP=y/# CONFIG_DEBUG_ATOMIC_SLEEP is not set/' config-nodebug
+	@perl -pi -e 's/CONFIG_DETECT_HUNG_TASK=y/# CONFIG_DETECT_HUNG_TASK is not set/' config-nodebug
 
 	@perl -pi -e 's/CONFIG_DEBUG_SET_MODULE_RONX=y/# CONFIG_DEBUG_SET_MODULE_RONX is not set/' config-nodebug
 
diff --git a/Makefile.config b/Makefile.config
index 75be683..d56185c 100644
--- a/Makefile.config
+++ b/Makefile.config
@@ -14,10 +14,9 @@ CONFIGFILES	= \
 	$(CFG)-armv7hl-omap.config $(CFG)-armv7hl-tegra.config \
 	$(CFG)-ppc.config $(CFG)-ppc-smp.config \
 	$(CFG)-sparc64.config  \
-	$(CFG)-ppc64.config $(CFG)-ppc64-debug.config \
-	$(CFG)-ia64.config
+	$(CFG)-ppc64.config $(CFG)-ppc64-debug.config
 
-PLATFORMS	= x86 x86_64 powerpc powerpc32 powerpc64 s390x ia64 sparc64
+PLATFORMS	= x86 x86_64 powerpc powerpc32 powerpc64 s390x sparc64
 TEMPFILES	= $(addprefix temp-, $(addsuffix -generic, $(PLATFORMS)))
 
 configs: $(CONFIGFILES)
@@ -44,16 +43,22 @@ temp-armv7l-omap-generic: config-arm-omap-generic temp-arm-generic
 temp-armv7l-tegra: config-arm-tegra temp-arm-generic
 	perl merge.pl $^  > $@
 
-temp-x86-generic: config-x86-generic temp-generic
+temp-x86-32: config-x86-32-generic config-x86-generic
 	perl merge.pl $^  > $@
 
-temp-x86-debug-generic: config-x86-generic temp-debug-generic
+temp-x86-32-generic: temp-x86-32 temp-generic
 	perl merge.pl $^  > $@
 
-temp-x86_64-generic: config-x86_64-generic temp-generic
+temp-x86-debug-generic: temp-x86-32 temp-debug-generic
 	perl merge.pl $^  > $@
 
-temp-x86_64-debug-generic: config-x86_64-generic temp-debug-generic
+temp-x86-64: config-x86_64-generic config-x86-generic
+	perl merge.pl $^  > $@
+
+temp-x86_64-generic: temp-x86-64 temp-generic
+	perl merge.pl $^  > $@
+
+temp-x86_64-debug-generic: temp-x86-64 temp-debug-generic
 	perl merge.pl $^  > $@
 
 temp-sparc64-generic: config-sparc64-generic temp-generic
@@ -71,16 +76,13 @@ temp-powerpc32-generic: config-powerpc32-generic temp-powerpc-generic
 temp-s390-generic: config-s390x temp-generic
 	perl merge.pl $^ > $@
 
-temp-ia64-generic: config-ia64-generic temp-generic
-	perl merge.pl $^ > $@
-
-kernel-$(VERSION)-i686-PAE.config: config-i686-PAE temp-x86-generic
+kernel-$(VERSION)-i686-PAE.config: config-i686-PAE temp-x86-32-generic
 	perl merge.pl $^ i386 > $@
 
 kernel-$(VERSION)-i686-PAEdebug.config: config-i686-PAE temp-x86-debug-generic
 	perl merge.pl $^ i386 > $@
 
-kernel-$(VERSION)-i686.config: /dev/null temp-x86-generic
+kernel-$(VERSION)-i686.config: /dev/null temp-x86-32-generic
 	perl merge.pl $^ i386 > $@
 
 kernel-$(VERSION)-i686-debug.config: /dev/null temp-x86-debug-generic
@@ -127,6 +129,3 @@ kernel-$(VERSION)-ppc.config: /dev/null temp-powerpc32-generic
 
 kernel-$(VERSION)-ppc-smp.config: config-powerpc32-smp temp-powerpc32-generic
 	perl merge.pl $^ powerpc > $@
-
-kernel-$(VERSION)-ia64.config: /dev/null temp-ia64-generic
-	perl merge.pl $^ ia64 > $@
diff --git a/add-appleir-usb-driver.patch b/add-appleir-usb-driver.patch
index 26477cc..0ab0ed6 100644
--- a/add-appleir-usb-driver.patch
+++ b/add-appleir-usb-driver.patch
@@ -140,9 +140,8 @@ diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
 index 60de906..2f2f2e7 100644
 --- a/drivers/input/misc/Kconfig
 +++ b/drivers/input/misc/Kconfig
-@@ -209,6 +209,19 @@ config INPUT_KEYSPAN_REMOTE
- 	  To compile this driver as a module, choose M here: the module will
- 	  be called keyspan_remote.
+ 	help
+ 	  Say Y here if you need accelerometer to work in polling mode.
  
 +config INPUT_APPLEIR
 +	tristate "Apple infrared receiver (built in)"
diff --git a/add-macbookair41-keyboard.patch b/add-macbookair41-keyboard.patch
new file mode 100644
index 0000000..bd5afda
--- /dev/null
+++ b/add-macbookair41-keyboard.patch
@@ -0,0 +1,119 @@
+Path: news.gmane.org!not-for-mail
+From: Pieter-Augustijn Van Malleghem <p-a at scarlet.be>
+Newsgroups: gmane.linux.kernel.input
+Subject: [PATCH] Add MacBookAir4,1 keyboard support
+Date: Wed, 7 Sep 2011 16:15:52 -0400
+Lines: 72
+Approved: news at gmane.org
+Message-ID: <20110907201552.GA1962 at Caligula>
+NNTP-Posting-Host: lo.gmane.org
+Mime-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+X-Trace: dough.gmane.org 1315426570 11003 80.91.229.12 (7 Sep 2011 20:16:10 GMT)
+X-Complaints-To: usenet at dough.gmane.org
+NNTP-Posting-Date: Wed, 7 Sep 2011 20:16:10 +0000 (UTC)
+To: linux-input at vger.kernel.org
+Original-X-From: linux-input-owner at vger.kernel.org Wed Sep 07 22:16:06 2011
+Return-path: <linux-input-owner at vger.kernel.org>
+Envelope-to: glki-linux-input-2 at lo.gmane.org
+Original-Received: from vger.kernel.org ([209.132.180.67])
+	by lo.gmane.org with esmtp (Exim 4.69)
+	(envelope-from <linux-input-owner at vger.kernel.org>)
+	id 1R1OXV-0007QX-Ll
+	for glki-linux-input-2 at lo.gmane.org; Wed, 07 Sep 2011 22:16:06 +0200
+Original-Received: (majordomo at vger.kernel.org) by vger.kernel.org via listexpand
+	id S1751419Ab1IGUQE (ORCPT <rfc822;glki-linux-input-2 at m.gmane.org>);
+	Wed, 7 Sep 2011 16:16:04 -0400
+Original-Received: from mail-vx0-f174.google.com ([209.85.220.174]:57168 "EHLO
+	mail-vx0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
+	with ESMTP id S1751237Ab1IGUQC (ORCPT
+	<rfc822;linux-input at vger.kernel.org>); Wed, 7 Sep 2011 16:16:02 -0400
+Original-Received: by vxj15 with SMTP id 15so31147vxj.19
+        for <linux-input at vger.kernel.org>; Wed, 07 Sep 2011 13:16:02 -0700 (PDT)
+Original-Received: by 10.52.69.210 with SMTP id g18mr64348vdu.133.1315426562281;
+        Wed, 07 Sep 2011 13:16:02 -0700 (PDT)
+Original-Received: from Caligula ([140.247.246.50])
+        by mx.google.com with ESMTPS id ch2sm944169vdc.19.2011.09.07.13.16.01
+        (version=TLSv1/SSLv3 cipher=OTHER);
+        Wed, 07 Sep 2011 13:16:01 -0700 (PDT)
+Content-Disposition: inline
+User-Agent: Mutt/1.5.21 (2010-09-15)
+Original-Sender: linux-input-owner at vger.kernel.org
+Precedence: bulk
+List-ID: <linux-input.vger.kernel.org>
+X-Mailing-List: linux-input at vger.kernel.org
+Xref: news.gmane.org gmane.linux.kernel.input:21462
+Archived-At: <http://permalink.gmane.org/gmane.linux.kernel.input/21462>
+
+This patch adds support for the Apple MacBookAir4,1 released in July 
+2011. It was inspired by Joshua Dillon's patch for the MacBookAir4,2
+posted on http://www.almostsure.com/mba42/hid-apple-dkms.patch.
+
+Signed-off-by: Pieter-Augustijn Van Malleghem <p-a at scarlet.be>
+diff -uNr linux/drivers/hid/hid-apple.c patched/drivers/hid/hid-apple.c
+--- linux/drivers/hid/hid-apple.c	2011-09-06 23:41:58.000000000 -0400
++++ patched/drivers/hid/hid-apple.c	2011-09-06 23:53:05.000000000 -0400
+@@ -183,6 +183,9 @@
+ 		if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
+ 				hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
+ 			table = macbookair_fn_keys;
++		else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI &&
++				hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS)
++			table = apple_fn_keys;
+ 		else if (hid->product < 0x21d || hid->product >= 0x300)
+ 			table = powerbook_fn_keys;
+ 		else
+@@ -493,6 +499,12 @@
+ 		.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
+ 		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI),
++		.driver_data = APPLE_HAS_FN },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO),
++		.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS),
++		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+ 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
+ 		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+ 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
+diff -uNr linux/drivers/hid/hid-core.c patched/drivers/hid/hid-core.c
+--- linux/drivers/hid/hid-core.c	2011-09-06 23:41:58.000000000 -0400
++++ patched/drivers/hid/hid-core.c	2011-09-06 23:56:22.000000000 -0400
+@@ -1340,6 +1340,9 @@
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) },
+@@ -1892,6 +1895,9 @@
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
++	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
+ 	{ }
+diff -uNr linux/drivers/hid/hid-ids.h patched/drivers/hid/hid-ids.h
+--- linux/drivers/hid/hid-ids.h	2011-09-06 23:41:58.000000000 -0400
++++ patched/drivers/hid/hid-ids.h	2011-09-06 23:57:39.000000000 -0400
+@@ -109,6 +109,9 @@
+ #define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI	0x0245
+ #define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO	0x0246
+ #define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS	0x0247
++#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI	0x0249
++#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO	0x024a
++#define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS	0x024b
+ #define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI	0x024f
+ #define USB_DEVICE_ID_APPLE_ALU_REVB_ISO	0x0250
+ #define USB_DEVICE_ID_APPLE_ALU_REVB_JIS	0x0251
+--
+To unsubscribe from this list: send the line "unsubscribe linux-input" in
+the body of a message to majordomo at vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
+
diff --git a/arm-omap-dt-compat.patch b/arm-omap-dt-compat.patch
index ab7cd0a..4046e93 100644
--- a/arm-omap-dt-compat.patch
+++ b/arm-omap-dt-compat.patch
@@ -16,7 +16,7 @@ diff -up linux-2.6.39.armv7l/arch/arm/mach-omap2/board-omap3beagle.c.fdt linux-2
 @@ -600,4 +605,5 @@ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagl
  	.init_irq	= omap3_beagle_init_irq,
  	.init_machine	= omap3_beagle_init,
- 	.timer		= &omap_timer,
+ 	.timer		= &omap3_secure_timer,
 +	.dt_compat      = omap3_beagle_dt_match,
  MACHINE_END
 diff -up linux-2.6.39.armv7l/arch/arm/mach-omap2/board-omap4panda.c.fdt linux-2.6.39.armv7l/arch/arm/mach-omap2/board-omap4panda.c
@@ -37,6 +37,6 @@ diff -up linux-2.6.39.armv7l/arch/arm/mach-omap2/board-omap4panda.c.fdt linux-2.
 @@ -717,4 +722,5 @@ MACHINE_START(OMAP4_PANDA, "OMAP4 Panda 
  	.init_irq	= gic_init_irq,
  	.init_machine	= omap4_panda_init,
- 	.timer		= &omap_timer,
+ 	.timer		= &omap4_timer,
 +	.dt_compat      = omap4_panda_match,
  MACHINE_END
diff --git a/config-arm-generic b/config-arm-generic
index 3886c6d..307c66d 100644
--- a/config-arm-generic
+++ b/config-arm-generic
@@ -9,6 +9,7 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_ARCH_VERSATILE=y
 CONFIG_ARCH_VERSATILE_PB=y
 CONFIG_MACH_VERSATILE_AB=y
+CONFIG_MACH_VERSATILE_DT=y
 
 CONFIG_HIGHMEM=y
 # CONFIG_HIGHPTE is not set
@@ -149,9 +150,13 @@ CONFIG_USE_OF=y
 CONFIG_PROC_DEVICETREE=y
 CONFIG_MTD_PHYSMAP_OF=m
 CONFIG_SERIAL_OF_PLATFORM=m
-# CONFIG_LEDS_GPIO_OF is not set
 CONFIG_MMC_SDHCI_OF=m
+CONFIG_MMC_SDHCI_PXAV3=m
+CONFIG_MMC_SDHCI_PXAV2=m
 
+CONFIG_FTGMAC100=m
+
+# disable TPM on arm at least on the trimslices it causes havoc
 # CONFIG_TCG_TPM is not set
 # CONFIG_IMA is not set
 
diff --git a/config-arm-omap-generic b/config-arm-omap-generic
index 560dfe6..8c3ae6a 100644
--- a/config-arm-omap-generic
+++ b/config-arm-omap-generic
@@ -276,6 +276,7 @@ CONFIG_TI_DAC7512=m
 CONFIG_BMP085=m
 CONFIG_C2PORT=m
 CONFIG_EEPROM_AT25=m
+CONFIG_EEPROM_93XX46=m
 # CONFIG_IWMC3200TOP_DEBUGFS is not set
 # CONFIG_SCSI_PROC_FS is not set
 # CONFIG_BLK_DEV_SR_VENDOR is not set
@@ -388,6 +389,7 @@ CONFIG_INPUT_AD714X_SPI=m
 # CONFIG_INPUT_APPLEIR is not set
 CONFIG_INPUT_TWL4030_PWRBUTTON=y
 CONFIG_INPUT_TWL4030_VIBRA=y
+CONFIG_INPUT_TWL6040_VIBRA=y
 CONFIG_INPUT_UINPUT=y
 # CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
 CONFIG_INPUT_ADXL34X=m
@@ -445,6 +447,7 @@ CONFIG_ARCH_REQUIRE_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
 CONFIG_GPIO_SYSFS=y
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
 
 #
 # Memory mapped GPIO expanders:
@@ -568,6 +571,7 @@ CONFIG_OMAP_WATCHDOG=y
 CONFIG_SSB=y
 # CONFIG_SSB_SDIOHOST is not set
 CONFIG_MFD_CORE=y
+# CONFIG_MFD_AAT2870_CORE is not set
 # CONFIG_MFD_88PM860X is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_MFD_ASIC3 is not set
@@ -597,6 +601,8 @@ CONFIG_TWL4030_CODEC=y
 CONFIG_MFD_OMAP_USB_HOST=y
 # CONFIG_MFD_TPS6586X is not set
 # CONFIG_MFD_TPS65910 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
+# CONFIG_MFD_TPS65912_SPI is not set
 # CONFIG_MFD_WL1273_CORE is not set
 CONFIG_REGULATOR=y
 # CONFIG_REGULATOR_DEBUG is not set
@@ -640,6 +646,7 @@ CONFIG_VIDEO_SAA717X=m
 CONFIG_VIDEO_SAA7127=m
 CONFIG_VIDEO_UPD64031A=m
 CONFIG_VIDEO_UPD64083=m
+CONFIG_VIDEO_ADP1653=m
 #
 # CONFIG_VIDEO_TVAUDIO is not set
 # CONFIG_VIDEO_TDA7432 is not set
@@ -699,7 +706,6 @@ CONFIG_FB_CFB_IMAGEBLIT=y
 # CONFIG_FB_ARMCLCD is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
-# CONFIG_FB_MB862XX is not set
 # CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
 # CONFIG_FB_OMAP_LCD_VGA is not set
 CONFIG_OMAP2_VRAM=y
@@ -736,6 +742,7 @@ CONFIG_PANEL_TPO_TD043MTEA1=y
 # CONFIG_LCD_VGG2432A4 is not set
 # CONFIG_LCD_PLATFORM is not set
 # CONFIG_LCD_S6E63M0 is not set
+# CONFIG_LCD_AMS369FG06 is not set
 CONFIG_BACKLIGHT_GENERIC=m
 CONFIG_DISPLAY_SUPPORT=y
 # CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
@@ -790,6 +797,7 @@ CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y
 CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE=y
 CONFIG_SND_OMAP_SOC_ZOOM2=y
 CONFIG_SND_OMAP_SOC_IGEP0020=y
+CONFIG_SND_OMAP_SOC_OMAP4_HDMI=y
 CONFIG_SND_SOC_I2C_AND_SPI=y
 # CONFIG_SND_SOC_ALL_CODECS is not set
 CONFIG_SND_SOC_TLV320AIC23=y
@@ -920,6 +928,7 @@ CONFIG_MMC_SPI=m
 # CONFIG_MEMSTICK is not set
 CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_GPIO_PLATFORM=y
+CONFIG_LEDS_GPIO_OF=y
 # CONFIG_LEDS_LP3944 is not set
 # CONFIG_LEDS_LP5521 is not set
 # CONFIG_LEDS_LP5523 is not set
@@ -1028,7 +1037,6 @@ CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_DEBUG_PREEMPT=y
 # CONFIG_BKL is not set
 # CONFIG_SPARSE_RCU_POINTER is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_HIGHMEM is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_LIST is not set
diff --git a/config-arm-tegra b/config-arm-tegra
index c8f1eec..910b39f 100644
--- a/config-arm-tegra
+++ b/config-arm-tegra
@@ -4,8 +4,8 @@ CONFIG_MACH_KAEN=y
 CONFIG_MACH_PAZ00=y
 CONFIG_MACH_TRIMSLICE=y
 CONFIG_MACH_WARIO=y
+CONFIG_MACH_TEGRA_DT=y
 CONFIG_TEGRA_DEBUG_UARTD=y
-CONFIG_ARM_ERRATA_742230=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -31,6 +31,7 @@ CONFIG_CACHE_L2X0=y
 CONFIG_ARM_ERRATA_430973=y
 # CONFIG_ARM_ERRATA_458693 is not set
 # CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_ARM_ERRATA_742230=y
 # CONFIG_ARM_ERRATA_742231 is not set
 CONFIG_PL310_ERRATA_588369=y
 CONFIG_ARM_ERRATA_720789=y
@@ -47,10 +48,11 @@ CONFIG_LOCAL_TIMERS=y
 CONFIG_HW_PERF_EVENTS=y
 # CONFIG_NEON is not set
 # CONFIG_RFKILL_GPIO is not set
+CONFIG_GPIO_GENERIC_PLATFORM=y
+# CONFIG_GPIO_MCP23S08 is not set
 CONFIG_KEYBOARD_TEGRA=y
 # CONFIG_MPCORE_WATCHDOG is not set
 CONFIG_USB_EHCI_TEGRA=y
-CONFIG_USB_STORAGE=y
 CONFIG_RTC_DRV_TEGRA=m
 
 CONFIG_SND_SOC_TEGRA=m
diff --git a/config-debug b/config-debug
index 7bbaa0b..a252390 100644
--- a/config-debug
+++ b/config-debug
@@ -2,6 +2,8 @@ CONFIG_SND_VERBOSE_PRINTK=y
 CONFIG_SND_DEBUG=y
 CONFIG_SND_PCM_XRUN_DEBUG=y
 
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+
 CONFIG_DEBUG_MUTEXES=y
 CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_DEBUG_LOCK_ALLOC=y
@@ -70,7 +72,7 @@ CONFIG_DEBUG_PERF_USE_VMALLOC=y
 
 CONFIG_JBD2_DEBUG=y
 
-CONFIG_DEBUG_CFQ_IOSCHED=y
+CONFIG_DEBUG_BLK_CGROUP=y
 
 CONFIG_DRBD_FAULT_INJECTION=y
 
@@ -98,3 +100,8 @@ CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
 CONFIG_TEST_LIST_SORT=y
 
 CONFIG_DEBUG_SET_MODULE_RONX=y
+
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+
diff --git a/config-generic b/config-generic
index 0a6785b..39851a2 100644
--- a/config-generic
+++ b/config-generic
@@ -45,7 +45,6 @@ CONFIG_LOG_BUF_SHIFT=17
 # CONFIG_EXPERT is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_IOSCHED_NOOP=y
@@ -92,7 +91,6 @@ CONFIG_PCI_STUB=y
 CONFIG_PCI_IOV=y
 CONFIG_HT_IRQ=y
 CONFIG_PCI_MSI=y
-CONFIG_PCI_MSI_DEFAULT_ON=y
 CONFIG_PCIEPORTBUS=y
 CONFIG_PCIEAER=y
 CONFIG_PCIEASPM=y
@@ -101,7 +99,6 @@ CONFIG_PCIE_ECRC=y
 CONFIG_PCIEAER_INJECT=m
 CONFIG_HOTPLUG_PCI_PCIE=y
 CONFIG_HOTPLUG_PCI_FAKE=m
-CONFIG_PCI_LEGACY=y
 
 CONFIG_ISA=y
 # CONFIG_EISA is not set
@@ -118,7 +115,6 @@ CONFIG_YENTA=m
 CONFIG_CARDBUS=y
 CONFIG_I82092=m
 CONFIG_PD6729=m
-CONFIG_PCMCIA_IOCTL=y
 
 CONFIG_PCCARD=y
 CONFIG_MMC=m
@@ -195,9 +191,7 @@ CONFIG_EXTRA_FIRMWARE=""
 CONFIG_MTD=m
 # CONFIG_MTD_DEBUG is not set
 CONFIG_MTD_SWAP=m
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_AR7_PARTS=m
-CONFIG_MTD_CONCAT=m
 CONFIG_MTD_CMDLINE_PARTS=y
 #
 # User Modules And Translation Layers
@@ -359,6 +353,7 @@ CONFIG_CISS_SCSI_TAPE=y
 CONFIG_BLK_DEV_DAC960=m
 CONFIG_BLK_DEV_UMEM=m
 CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_OSD=m
@@ -375,6 +370,7 @@ CONFIG_BLK_DEV_DELKIN=m
 # CONFIG_BLK_DEV_TC86C001 is not set
 CONFIG_LBDAF=y
 CONFIG_BLK_DEV_BSG=y
+CONFIG_BLK_DEV_BSGLIB=y
 CONFIG_BLK_DEV_INTEGRITY=y
 CONFIG_BLK_DEV_THROTTLING=y
 
@@ -486,7 +482,6 @@ CONFIG_SCSI_SAS_ATTRS=m
 CONFIG_SCSI_SRP_TGT_ATTRS=y
 CONFIG_SCSI_SAS_LIBSAS=m
 CONFIG_SCSI_SAS_ATA=y
-# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set
 CONFIG_SCSI_SAS_HOST_SMP=y
 CONFIG_RAID_ATTRS=m
 
@@ -528,6 +523,7 @@ CONFIG_MEGARAID_LEGACY=m
 CONFIG_MEGARAID_SAS=m
 CONFIG_SCSI_MVSAS=m
 # CONFIG_SCSI_MVSAS_DEBUG is not set
+CONFIG_SCSI_MVSAS_TASKLET=y
 CONFIG_SCSI_MPT2SAS=m
 CONFIG_SCSI_MPT2SAS_MAX_SGE=128
 CONFIG_SCSI_MPT2SAS_LOGGING=y
@@ -725,7 +721,6 @@ CONFIG_FIREWIRE_NOSY=m
 #
 # IEEE 1394 (FireWire) support
 #
-# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
@@ -734,6 +729,10 @@ CONFIG_FIREWIRE_NOSY=m
 # CONFIG_I2O_LCT_NOTIFY_ON_CHANGES is not set
 
 #
+# Virtualization support drivers
+#
+# CONFIG_VIRT_DRIVERS is not set
+
 # Networking support
 #
 CONFIG_NET=y
@@ -758,7 +757,6 @@ CONFIG_TCP_MD5SIG=y
 # Networking options
 #
 CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=m
 CONFIG_NET_KEY_MIGRATE=y
@@ -844,9 +842,7 @@ CONFIG_NET_9P_VIRTIO=m
 # CONFIG_NET_9P_DEBUG is not set
 CONFIG_NET_9P_RDMA=m
 
-CONFIG_DECNET=m
-CONFIG_DECNET_ROUTER=y
-# CONFIG_DECNET_NF_GRABULATOR is not set
+# CONFIG_DECNET is not set
 CONFIG_BRIDGE=m
 CONFIG_BRIDGE_IGMP_SNOOPING=y
 # CONFIG_NETWORK_PHY_TIMESTAMPING is not set
@@ -924,7 +920,6 @@ CONFIG_BRIDGE_NETFILTER=y
 # IP: Netfilter Configuration
 #
 
-CONFIG_NF_CT_ACCT=y
 CONFIG_NF_CONNTRACK_MARK=y
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
@@ -950,7 +945,6 @@ CONFIG_NF_CT_PROTO_SCTP=m
 CONFIG_NF_CT_NETLINK=m
 CONFIG_NF_CT_PROTO_UDPLITE=m
 
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_TTL=m
@@ -1043,6 +1037,7 @@ CONFIG_IP_SET_HASH_IPPORTIP=m
 CONFIG_IP_SET_HASH_IPPORTNET=m
 CONFIG_IP_SET_HASH_NET=m
 CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 
 #
@@ -1076,7 +1071,6 @@ CONFIG_IP_DCCP_CCID2=m
 # CONFIG_IP_DCCP_CCID2_DEBUG is not set
 CONFIG_IP_DCCP_CCID3=y
 # CONFIG_IP_DCCP_CCID3_DEBUG is not set
-CONFIG_IP_DCCP_CCID3_RTO=100
 # CONFIG_IP_DCCP_DEBUG is not set
 CONFIG_NET_DCCPPROBE=m
 
@@ -1300,7 +1294,6 @@ CONFIG_ATL1E=m
 CONFIG_E100=m
 CONFIG_FEALNX=m
 CONFIG_FORCEDETH=m
-CONFIG_FORCEDETH_NAPI=y
 CONFIG_NATSEMI=m
 CONFIG_NE2K_PCI=m
 CONFIG_8139CP=m
@@ -1344,9 +1337,9 @@ CONFIG_NS83820=m
 CONFIG_HAMACHI=m
 CONFIG_YELLOWFIN=m
 CONFIG_R8169=m
-CONFIG_R8169_VLAN=y
 CONFIG_SKGE=m
 # CONFIG_SKGE_DEBUG is not set
+CONFIG_SKGE_GENESIS=y
 CONFIG_TIGON3=m
 CONFIG_SKY2=m
 # CONFIG_SKY2_DEBUG is not set
@@ -1410,9 +1403,6 @@ CONFIG_SLIP_SMART=y
 #
 CONFIG_WLAN=y
 # CONFIG_STRIP is not set
-# CONFIG_ARLAN is not set
-CONFIG_PCMCIA_WAVELAN=m
-CONFIG_PCMCIA_NETWAVE=m
 # CONFIG_PCMCIA_RAYCS is not set
 
 CONFIG_WIRELESS=y
@@ -1424,7 +1414,6 @@ CONFIG_CFG80211_DEBUGFS=y
 CONFIG_CFG80211_DEFAULT_PS=y
 CONFIG_NL80211=y
 # CONFIG_NL80211_TESTMODE is not set
-# CONFIG_WIRELESS_OLD_REGULATORY is not set
 CONFIG_WIRELESS_EXT=y
 CONFIG_WIRELESS_EXT_SYSFS=y
 CONFIG_LIB80211=m
@@ -1472,6 +1461,7 @@ CONFIG_ATMEL=m
 CONFIG_B43=m
 CONFIG_B43_PCMCIA=y
 CONFIG_B43_SDIO=y
+CONFIG_B43_BCMA=y
 # CONFIG_B43_DEBUG is not set
 CONFIG_B43_PHY_LP=y
 CONFIG_B43_PHY_N=y
@@ -1514,7 +1504,6 @@ CONFIG_LIBERTAS_MESH=y
 CONFIG_IWLWIFI=m
 CONFIG_IWLWIFI_DEBUG=y
 CONFIG_IWLWIFI_DEBUGFS=y
-CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT=y
 CONFIG_IWLWIFI_DEVICE_SVTOOL=y
 # CONFIG_IWL_P2P is not set
 CONFIG_IWLAGN=m
@@ -1523,9 +1512,7 @@ CONFIG_IWLWIFI_LEGACY_DEBUG=y
 CONFIG_IWLWIFI_LEGACY_DEBUGFS=y
 # CONFIG_IWLWIFI_LEGACY_DEVICE_TRACING is not set
 CONFIG_IWL4965=y
-CONFIG_IWL5000=y
 CONFIG_IWL3945=m
-CONFIG_IWL3945_SPECTRUM_MEASUREMENT=y
 # CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE is not set
 CONFIG_IWM=m
 # CONFIG_IWM_DEBUG is not set
@@ -1566,7 +1553,6 @@ CONFIG_USB_NET_KALMIA=m
 CONFIG_USB_NET_SMSC75XX=m
 CONFIG_ZD1211RW=m
 # CONFIG_ZD1211RW_DEBUG is not set
-CONFIG_AR9170_USB=m
 
 CONFIG_WL12XX_MENU=m
 CONFIG_WL12XX=m
@@ -1578,13 +1564,11 @@ CONFIG_WL12XX_SDIO=m
 CONFIG_WL1251=m
 CONFIG_WL1251_SPI=m
 CONFIG_WL1251_SDIO=m
-CONFIG_WL1271=m
-CONFIG_WL1271_SDIO=m
-CONFIG_WL1271_SPI=m
 
 CONFIG_RTL8192CE=m
 CONFIG_RTL8192SE=m
 CONFIG_RTL8192CU=m
+CONFIG_RTL8192DE=m
 
 CONFIG_MWIFIEX=m
 CONFIG_MWIFIEX_SDIO=m
@@ -1665,6 +1649,8 @@ CONFIG_BAYCOM_PAR=m
 CONFIG_BAYCOM_EPP=m
 CONFIG_YAM=m
 
+CONFIG_NFC=m
+
 #
 # IrDA (infrared) support
 #
@@ -1708,7 +1694,6 @@ CONFIG_WINBOND_FIR=m
 #
 CONFIG_BT=m
 CONFIG_BT_L2CAP=y
-CONFIG_BT_L2CAP_EXT_FEATURES=y
 CONFIG_BT_SCO=y
 CONFIG_BT_CMTP=m
 CONFIG_BT_RFCOMM=m
@@ -1833,8 +1818,6 @@ CONFIG_ISDN_CAPI=m
 CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y
 CONFIG_ISDN_CAPI_MIDDLEWARE=y
 CONFIG_ISDN_CAPI_CAPI20=m
-CONFIG_ISDN_CAPI_CAPIFS_BOOL=y
-CONFIG_ISDN_CAPI_CAPIFS=m
 
 #
 # CAPI hardware drivers
@@ -1999,7 +1982,6 @@ CONFIG_TOUCHSCREEN_INEXIO=m
 CONFIG_TOUCHSCREEN_MTOUCH=m
 CONFIG_TOUCHSCREEN_MCS5000=m
 CONFIG_TOUCHSCREEN_MK712=m
-# CONFIG_TOUCHSCREEN_QT602240 is not set
 CONFIG_TOUCHSCREEN_PENMOUNT=m
 # CONFIG_TOUCHSCREEN_TPS6507X is not set
 CONFIG_TOUCHSCREEN_TSC2007=m
@@ -2031,10 +2013,13 @@ CONFIG_MAC_EMUMOUSEBTN=y
 
 CONFIG_INPUT_WM831X_ON=m
 
-CONFIG_INPUT_APPLEIR=m
 
 # CONFIG_INPUT_AD714X is not set
 # CONFIG_INPUT_PCF8574 is not set
+CONFIG_INPUT_MMA8450=m
+CONFIG_INPUT_MPU3050=m
+CONFIG_INPUT_KXTJ9=m
+# CONFIG_INPUT_KXTJ9_POLLED_MODE is not set
 
 #
 # Character devices
@@ -2075,19 +2060,12 @@ CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 # CONFIG_SERIAL_8250_DETECT_IRQ is not set
 CONFIG_SERIAL_8250_RSA=y
-# CONFIG_COMPUTONE is not set
 CONFIG_CYCLADES=m
 # CONFIG_CYZ_INTR is not set
-# CONFIG_DIGIEPCA is not set
 # CONFIG_MOXA_INTELLIO is not set
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
-# CONFIG_RISCOM8 is not set
-# CONFIG_SPECIALIX is not set
-# CONFIG_SX is not set
 # CONFIG_RIO is not set
-# CONFIG_STALLION is not set
-# CONFIG_ISTALLION is not set
 CONFIG_SERIAL_JSM=m
 # CONFIG_SERIAL_MFD_HSU is not set
 
@@ -2138,7 +2116,6 @@ CONFIG_I2C_ALGOPCA=m
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
 # CONFIG_I2C_ELEKTOR is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_ISCH is not set
@@ -2191,7 +2168,6 @@ CONFIG_SENSORS_ADM9240=m
 CONFIG_SENSORS_ADS7828=m
 CONFIG_SENSORS_ADT7462=m
 CONFIG_SENSORS_ADT7470=m
-CONFIG_SENSORS_ADT7473=m
 CONFIG_SENSORS_ADT7475=m
 CONFIG_SENSORS_APPLESMC=m
 CONFIG_SENSORS_ASB100=m
@@ -2231,6 +2207,7 @@ CONFIG_SENSORS_LM93=m
 CONFIG_SENSORS_LTC4245=m
 CONFIG_SENSORS_MAX1619=m
 CONFIG_SENSORS_MAX6650=m
+CONFIG_SENSORS_NTC_THERMISTOR=m
 CONFIG_SENSORS_PC87360=m
 CONFIG_SENSORS_PC87427=m
 CONFIG_SENSORS_PCF8591=m
@@ -2261,6 +2238,7 @@ CONFIG_SENSORS_W83792D=m
 CONFIG_SENSORS_W83793=m
 CONFIG_SENSORS_LTC4215=m
 CONFIG_SENSORS_LM95241=m
+CONFIG_SENSORS_LM95245=m
 CONFIG_SENSORS_TMP421=m
 CONFIG_SENSORS_WM8350=m
 CONFIG_SENSORS_WM831X=m
@@ -2284,6 +2262,7 @@ CONFIG_SENSORS_LINEAGE=m
 CONFIG_SENSORS_LTC4151=m
 CONFIG_SENSORS_MAX6639=m
 CONFIG_SENSORS_SCH5627=m
+CONFIG_SENSORS_SCH5636=m
 CONFIG_SENSORS_ADS1015=m
 CONFIG_SENSORS_MAX16065=m
 CONFIG_SENSORS_MAX6642=m
@@ -2295,13 +2274,16 @@ CONFIG_SENSORS_EMC6W201=m
 CONFIG_PMBUS=m
 CONFIG_SENSORS_PMBUS=m
 CONFIG_SENSORS_MAX16064=m
+CONFIG_SENSORS_LM25066=m
 CONFIG_SENSORS_MAX34440=m
 CONFIG_SENSORS_MAX8688=m
+CONFIG_SENSORS_MAX1668=m
 
 # CONFIG_HMC6352 is not set
 # CONFIG_BMP085 is not set
 # CONFIG_PCH_PHUB is not set
 # CONFIG_SERIAL_PCH_UART is not set
+# CONFIG_USB_SWITCH_FSA9480 is not set
 
 CONFIG_W1=m
 CONFIG_W1_CON=y
@@ -2341,6 +2323,7 @@ CONFIG_IPMI_POWEROFF=m
 # Watchdog Cards
 #
 CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_CORE=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 CONFIG_SOFT_WATCHDOG=m
 CONFIG_WDTPCI=m
@@ -2375,6 +2358,7 @@ CONFIG_USBPCWATCHDOG=m
 CONFIG_WM8350_WATCHDOG=m
 CONFIG_WM831X_WATCHDOG=m
 # CONFIG_MAX63XX_WATCHDOG is not set
+# CONFIG_DW_WATCHDOG is not set
 
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_TIMERIOMEM=m
@@ -2454,7 +2438,6 @@ CONFIG_DRM_R128=m
 CONFIG_DRM_RADEON=m
 CONFIG_DRM_RADEON_KMS=y
 CONFIG_DRM_I810=m
-# CONFIG_DRM_I830 is not set
 CONFIG_DRM_MGA=m
 CONFIG_DRM_SIS=m
 CONFIG_DRM_SAVAGE=m
@@ -2489,8 +2472,6 @@ CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=m
 # CONFIG_VIDEO_ADV_DEBUG is not set
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-CONFIG_VIDEO_ALLOW_V4L1=y
-CONFIG_VIDEO_V4L1_COMPAT=y
 CONFIG_VIDEO_V4L2=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 # CONFIG_VIDEO_VIVI is not set
@@ -2526,6 +2507,7 @@ CONFIG_VIDEO_CX88_VP3054=m
 CONFIG_VIDEO_EM28XX=m
 CONFIG_VIDEO_EM28XX_ALSA=m
 CONFIG_VIDEO_EM28XX_DVB=m
+CONFIG_VIDEO_EM28XX_RC=y
 CONFIG_VIDEO_CX231XX=m
 CONFIG_VIDEO_CX231XX_ALSA=m
 CONFIG_VIDEO_CX231XX_DVB=m
@@ -2535,17 +2517,13 @@ CONFIG_VIDEO_HEXIUM_GEMINI=m
 CONFIG_VIDEO_IVTV=m
 CONFIG_VIDEO_MEYE=m
 CONFIG_VIDEO_MXB=m
-# CONFIG_VIDEO_OVCAMCHIP is not set
 CONFIG_VIDEO_PVRUSB2_DVB=y
 CONFIG_VIDEO_HDPVR=m
-CONFIG_VIDEO_SAA5246A=m
-CONFIG_VIDEO_SAA5249=m
 CONFIG_VIDEO_SAA6588=m
 CONFIG_VIDEO_SAA7134=m
 CONFIG_VIDEO_SAA7134_ALSA=m
 CONFIG_VIDEO_SAA7134_DVB=m
 CONFIG_VIDEO_SAA7134_RC=y
-CONFIG_VIDEO_STRADIS=m
 CONFIG_VIDEO_USBVISION=m
 CONFIG_VIDEO_W9966=m
 CONFIG_VIDEO_ZORAN=m
@@ -2568,9 +2546,7 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
 #
 # Radio Adapters
 #
-CONFIG_RADIO_GEMTEK_PCI=m
 CONFIG_RADIO_MAXIRADIO=m
-CONFIG_RADIO_MAESTRO=m
 CONFIG_RADIO_WL1273=m
 CONFIG_RADIO_WL128X=m
 
@@ -2587,6 +2563,7 @@ CONFIG_MEDIA_TUNER_MT2131=m
 CONFIG_MEDIA_TUNER_QT1010=m
 CONFIG_MEDIA_TUNER_XC2028=m
 CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_XC4000=m
 CONFIG_MEDIA_TUNER_MXL5005S=m
 CONFIG_MEDIA_TUNER_MXL5007T=m
 CONFIG_MEDIA_TUNER_MC44S803=m
@@ -2599,6 +2576,7 @@ CONFIG_MEDIA_TUNER_TDA18212=m
 #
 CONFIG_DVB_CAPTURE_DRIVERS=y
 CONFIG_DVB_CORE=m
+CONFIG_DVB_NET=y
 CONFIG_DVB_MAX_ADAPTERS=8
 CONFIG_DVB_DYNAMIC_MINORS=y
 
@@ -2607,6 +2585,8 @@ CONFIG_DVB_STB0899=m
 CONFIG_DVB_STB6100=m
 CONFIG_DVB_STV090x=m
 CONFIG_DVB_STV6110x=m
+CONFIG_DVB_DRXK=m
+CONFIG_DVB_TDA18271C2DD=m
 CONFIG_DVB_CX24110=m
 CONFIG_DVB_CX24123=m
 CONFIG_DVB_MT312=m
@@ -2684,14 +2664,13 @@ CONFIG_DVB_USB_DW2102=m
 CONFIG_DVB_USB_FRIIO=m
 CONFIG_DVB_USB_EC168=m
 CONFIG_DVB_DM1105=m
-CONFIG_DVB_DRX397XD=m
-CONFIG_DVB_LGDT3304=m
 CONFIG_DVB_S921=m
 CONFIG_DVB_ISL6405=m
 CONFIG_DVB_LGS8GL5=m
 CONFIG_DVB_DUMMY_FE=m
 CONFIG_DVB_FIREDTV=m
 CONFIG_DVB_NGENE=m
+CONFIG_DVB_DDBRIDGE=m
 CONFIG_DVB_MB86A20S=m
 CONFIG_DVB_USB_TECHNISAT_USB2=m
 CONFIG_DVB_DIB9000=m
@@ -2769,6 +2748,7 @@ CONFIG_IR_RC6_DECODER=m
 CONFIG_IR_JVC_DECODER=m
 CONFIG_IR_SONY_DECODER=m
 CONFIG_IR_RC5_SZ_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
 CONFIG_IR_LIRC_CODEC=m
 CONFIG_IR_IMON=m
 CONFIG_IR_MCEUSB=m
@@ -2862,10 +2842,7 @@ CONFIG_FB_VIA=m
 CONFIG_FB_VIA_X_COMPATIBILITY=y
 # CONFIG_FB_VIA_DIRECT_PROCFS is not set
 CONFIG_FB_METRONOME=m
-CONFIG_FB_MB862XX=m
-CONFIG_FB_MB862XX_PCI_GDC=y
-CONFIG_FB_MB862XX_LIME=y
-CONFIG_FB_MB862XX_I2C=y
+# CONFIG_FB_MB862XX is not set
 # CONFIG_FB_PRE_INIT_FB is not set
 # CONFIG_FB_TMIO is not set
 # CONFIG_FB_BROADSHEET is not set
@@ -2988,24 +2965,23 @@ CONFIG_SND_HDA_INPUT_JACK=y
 CONFIG_SND_HDA_PATCH_LOADER=y
 CONFIG_SND_HDA_HWDEP=y
 CONFIG_SND_HDA_CODEC_REALTEK=y
+CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS=y
 CONFIG_SND_HDA_CODEC_CA0110=y
 CONFIG_SND_HDA_CODEC_ANALOG=y
 CONFIG_SND_HDA_CODEC_SIGMATEL=y
 CONFIG_SND_HDA_CODEC_VIA=y
-CONFIG_SND_HDA_CODEC_ATIHDMI=y
 CONFIG_SND_HDA_CODEC_CIRRUS=y
 CONFIG_SND_HDA_CODEC_CONEXANT=y
 CONFIG_SND_HDA_CODEC_CMEDIA=y
-CONFIG_SND_HDA_CODEC_INTELHDMI=y
 CONFIG_SND_HDA_CODEC_SI3054=y
-CONFIG_SND_HDA_CODEC_NVHDMI=y
 CONFIG_SND_HDA_CODEC_HDMI=y
+CONFIG_SND_HDA_CODEC_CA0132=y
 CONFIG_SND_HDA_GENERIC=y
 CONFIG_SND_HDA_POWER_SAVE=y
 CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0
 CONFIG_SND_HDA_RECONFIG=y
+CONFIG_SND_HDA_PREALLOC_SIZE=4096
 CONFIG_SND_HDSPM=m
-CONFIG_SND_HIFIER=m
 CONFIG_SND_ICE1712=m
 CONFIG_SND_ICE1724=m
 CONFIG_SND_INTEL8X0=y
@@ -3154,18 +3130,13 @@ CONFIG_USB_IDMOUSE=m
 CONFIG_DRAGONRISE_FF=y
 CONFIG_GREENASIA_FF=y
 CONFIG_SMARTJOYPLUS_FF=y
-CONFIG_HID_3M_PCT=y
 CONFIG_LOGIG940_FF=y
 CONFIG_HID_MAGICMOUSE=y
-CONFIG_HID_MOSART=y
 CONFIG_HID_MULTITOUCH=m
 CONFIG_HID_NTRIG=y
 CONFIG_HID_QUANTA=y
-CONFIG_HID_STANTUM=y
-CONFIG_HID_CANDO=m
 CONFIG_HID_PRODIKEYS=m
 CONFIG_HID_DRAGONRISE=m
-CONFIG_HID_EGALAX=m
 CONFIG_HID_GYRATION=m
 CONFIG_HID_TWINHAN=m
 CONFIG_HID_ORTEK=m
@@ -3195,6 +3166,10 @@ CONFIG_HID_KEYTOUCH=m
 CONFIG_HID_LCPOWER=m
 CONFIG_HID_ROCCAT_ARVO=m
 CONFIG_HID_ROCCAT_KOVAPLUS=m
+CONFIG_HID_HOLTEK=m
+CONFIG_HOLTEK_FF=y
+CONFIG_HID_SPEEDLINK=m
+CONFIG_HID_WIIMOTE=m
 
 #
 # USB Imaging devices
@@ -3205,10 +3180,7 @@ CONFIG_USB_MICROTEK=m
 #
 # USB Multimedia devices
 #
-CONFIG_DAB=y
-CONFIG_USB_DABUSB=m
 
-CONFIG_USB_VICAM=m
 CONFIG_USB_DSBR=m
 # CONFIG_USB_ET61X251 is not set
 CONFIG_USB_M5602=m
@@ -3228,7 +3200,6 @@ CONFIG_USB_GSPCA_PAC207=m
 CONFIG_USB_GSPCA_PAC7311=m
 CONFIG_USB_GSPCA_SN9C2028=m
 CONFIG_USB_GSPCA_SN9C20X=m
-CONFIG_USB_GSPCA_SN9C20X_EVDEV=y
 CONFIG_USB_GSPCA_SONIXB=m
 CONFIG_USB_GSPCA_SONIXJ=m
 CONFIG_USB_GSPCA_SPCA500=m
@@ -3256,15 +3227,11 @@ CONFIG_USB_GSPCA_SQ930X=m
 CONFIG_USB_GSPCA_NW80X=m
 CONFIG_USB_GSPCA_VICAM=m
 CONFIG_USB_GSPCA_KINECT=m
+CONFIG_USB_GSPCA_SE401=m
 
-CONFIG_USB_IBMCAM=m
-CONFIG_USB_KONICAWC=m
-# CONFIG_USB_OV511 is not set
 CONFIG_USB_S2255=m
-CONFIG_USB_SE401=m
 # CONFIG_VIDEO_SH_MOBILE_CEU is not set
 # CONFIG_VIDEO_SH_MOBILE_CSI2 is not set
-# CONFIG_USB_STV680 is not set
 # CONFIG_USB_SN9C102 is not set
 CONFIG_USB_ZR364XX=m
 CONFIG_SOC_CAMERA=m
@@ -3279,6 +3246,7 @@ CONFIG_SOC_CAMERA_MT9T112=m
 CONFIG_SOC_CAMERA_RJ54N1=m
 CONFIG_SOC_CAMERA_OV9640=m
 CONFIG_SOC_CAMERA_OV6650=m
+CONFIG_SOC_CAMERA_OV5642=m
 CONFIG_SOC_CAMERA_IMX074=m
 CONFIG_SOC_CAMERA_OV2640=m
 CONFIG_SOC_CAMERA_OV9740=m
@@ -3399,7 +3367,6 @@ CONFIG_USB_SERIAL_QCAUX=m
 CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m
 CONFIG_USB_SERIAL_DEBUG=m
 CONFIG_USB_SERIAL_SSU100=m
-CONFIG_USB_SERIAL_SAMBA=m
 
 CONFIG_USB_SERIAL_CONSOLE=y
 
@@ -3418,7 +3385,6 @@ CONFIG_USB_SEVSEG=m
 CONFIG_USB_ALI_M5632=y
 CONFIG_USB_APPLEDISPLAY=m
 CONFIG_USB_ATM=m
-CONFIG_USB_BERRY_CHARGE=m
 CONFIG_USB_CXACRU=m
 # CONFIG_USB_C67X00_HCD is not set
 # CONFIG_USB_CYTHERM is not set
@@ -3428,7 +3394,6 @@ CONFIG_USB_FTDI_ELAN=m
 CONFIG_USB_FILE_STORAGE=m
 # CONFIG_USB_FILE_STORAGE_TEST is not set
 # CONFIG_USB_GADGET is not set
-# CONFIG_USB_GADGET_GOKU is not set
 # CONFIG_USB_GADGETFS is not set
 # CONFIG_USB_ISP116X_HCD is not set
 # CONFIG_USB_ISP1760_HCD is not set
@@ -3436,7 +3401,6 @@ CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_IOWARRIOR=m
 CONFIG_USB_ISIGHTFW=m
 CONFIG_USB_YUREX=m
-CONFIG_USB_VST=m
 CONFIG_USB_LCD=m
 CONFIG_USB_LD=m
 CONFIG_USB_LEGOTOWER=m
@@ -3445,7 +3409,6 @@ CONFIG_USB_PWC=m
 CONFIG_USB_PWC_INPUT_EVDEV=y
 # CONFIG_USB_PWC_DEBUG is not set
 # CONFIG_USB_RIO500 is not set
-# CONFIG_USB_QUICKCAM_MESSENGER is not set
 CONFIG_USB_SISUSBVGA=m
 CONFIG_USB_SISUSBVGA_CON=y
 CONFIG_RADIO_SI470X=y
@@ -3460,7 +3423,6 @@ CONFIG_USB_TRANCEVIBRATOR=m
 CONFIG_USB_U132_HCD=m
 CONFIG_USB_UEAGLEATM=m
 CONFIG_USB_XUSBATM=m
-# CONFIG_USB_ZC0301 is not set
 CONFIG_USB_ZERO=m
 
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
@@ -3512,7 +3474,7 @@ CONFIG_MFD_WM8400=m
 # CONFIG_MFD_RDC321X is not set
 # CONFIG_MFD_JANZ_CMODIO is not set
 # CONFIG_MFD_WM831X_I2C is not set
-CONFIG_MFD_CS5535=m
+# CONFIG_MFD_CS5535 is not set
 
 #
 # File systems
@@ -3563,7 +3525,6 @@ CONFIG_QFMT_V2=y
 CONFIG_QUOTACTL=y
 CONFIG_DNOTIFY=y
 # Autofsv3 is obsolete.
-# CONFIG_AUTOFS_FS is not set
 # systemd is dependant upon AUTOFS, so build it in.
 CONFIG_AUTOFS4_FS=y
 CONFIG_EXOFS_FS=m
@@ -3641,6 +3602,7 @@ CONFIG_SQUASHFS=m
 CONFIG_SQUASHFS_XATTR=y
 CONFIG_SQUASHFS_LZO=y
 CONFIG_SQUASHFS_XZ=y
+CONFIG_SQUASHFS_ZLIB=y
 # CONFIG_SQUASHFS_EMBEDDED is not set
 CONFIG_VXFS_FS=m
 # CONFIG_HPFS_FS is not set
@@ -3672,8 +3634,8 @@ CONFIG_NFSD_V4=y
 CONFIG_NFS_FSCACHE=y
 # CONFIG_NFS_USE_LEGACY_DNS is not set
 # CONFIG_NFS_USE_NEW_IDMAPPER is not set
-# CONFIG_NFSD_DEPRECATED is not set
 CONFIG_PNFS_OBJLAYOUT=m
+CONFIG_PNFS_BLOCK=m
 CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
@@ -3681,13 +3643,9 @@ CONFIG_SUNRPC=m
 CONFIG_SUNRPC_GSS=m
 CONFIG_SUNRPC_XPRT_RDMA=m
 CONFIG_RPCSEC_GSS_KRB5=m
-CONFIG_RPCSEC_GSS_SPKM3=m
-# CONFIG_SMB_FS is not set
-# CONFIG_SMB_NLS_DEFAULT is not set
 CONFIG_CIFS=m
 CONFIG_CIFS_STATS=y
 # CONFIG_CIFS_STATS2 is not set
-CONFIG_CIFS_EXPERIMENTAL=y
 CONFIG_CIFS_UPCALL=y
 CONFIG_CIFS_XATTR=y
 CONFIG_CIFS_POSIX=y
@@ -3931,6 +3889,8 @@ CONFIG_CRC32=m
 CONFIG_CRC_CCITT=m
 CONFIG_CRC_ITU_T=m
 CONFIG_CRC_T10DIF=m
+CONFIG_CRC8=m
+CONFIG_CORDIC=m
 
 CONFIG_CRYPTO_ZLIB=m
 CONFIG_ZLIB_INFLATE=y
@@ -3967,7 +3927,6 @@ CONFIG_SCHEDSTATS=y
 CONFIG_SCHED_DEBUG=y
 CONFIG_FAIR_GROUP_SCHED=y
 CONFIG_SCHED_OMIT_FRAME_POINTER=y
-CONFIG_GROUP_SCHED=y
 CONFIG_RT_GROUP_SCHED=y
 CONFIG_SCHED_AUTOGROUP=y
 
@@ -3976,14 +3935,13 @@ CONFIG_PROC_PID_CPUSET=y
 
 CONFIG_CGROUPS=y
 # CONFIG_CGROUP_DEBUG is not set
-CONFIG_CGROUP_NS=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_CGROUP_DEVICE=y
 CONFIG_CGROUP_FREEZER=y
 CONFIG_CGROUP_SCHED=y
 CONFIG_CGROUP_MEM_RES_CTLR=y
 CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y # XXX disabled by default, pass 'swapaccount'
-# CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED is not set 
+# CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED is not set
 CONFIG_CGROUP_PERF=y
 CONFIG_BLK_CGROUP=y
 # CONFIG_DEBUG_BLK_CGROUP is not set
@@ -4015,6 +3973,19 @@ CONFIG_PM_TRACE=y
 # CONFIG_PM_TEST_SUSPEND is not set
 CONFIG_PM_RUNTIME=y
 
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEBUG=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_CPU_FREQ_TABLE=y
+CONFIG_CPU_FREQ_STAT=m
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+
 ## BEGIN ISA Junk.
 
 CONFIG_I82365=m
@@ -4074,7 +4045,6 @@ CONFIG_EWRK3=m
 # CONFIG_SKISA is not set
 # CONFIG_PROTEON is not set
 # CONFIG_SMCTR is not set
-# CONFIG_WAVELAN is not set
 # CONFIG_HISAX_16_0 is not set
 # CONFIG_HISAX_AVM_A1 is not set
 # CONFIG_HISAX_IX1MICROR2 is not set
@@ -4127,7 +4097,6 @@ CONFIG_RADIO_ADAPTERS=y
 # CONFIG_SND_AD1848 is not set
 # CONFIG_SND_CS4231 is not set
 CONFIG_SND_CS4236=m
-# CONFIG_SND_ES968 is not set
 # CONFIG_SND_ES1688 is not set
 # CONFIG_SND_ES18XX is not set
 # CONFIG_SND_GUSCLASSIC is not set
@@ -4146,9 +4115,7 @@ CONFIG_SND_SBAWE=m
 # CONFIG_SND_ALS100 is not set
 # CONFIG_SND_AZT2320 is not set
 # CONFIG_SND_CMI8330 is not set
-# CONFIG_SND_DT019X is not set
 CONFIG_SND_OPL3SA2=m
-# CONFIG_SND_SGALAXY is not set
 # CONFIG_SND_SSCAPE is not set
 CONFIG_SND_DARLA20=m
 CONFIG_SND_GINA20=m
@@ -4175,6 +4142,7 @@ CONFIG_LEDS_CLASS=y
 # CONFIG_LEDS_AMS_DELTA is not set
 # CONFIG_LEDS_LOCOMO is not set
 # CONFIG_LEDS_NET48XX is not set
+# CONFIG_LEDS_NET5501 is not set
 # CONFIG_LEDS_PCA9532 is not set
 # CONFIG_LEDS_PCA955X is not set
 # CONFIG_LEDS_BD2802 is not set
@@ -4215,9 +4183,7 @@ CONFIG_DYNAMIC_FTRACE=y
 # CONFIG_IRQSOFF_TRACER is not set
 CONFIG_SCHED_TRACER=y
 CONFIG_CONTEXT_SWITCH_TRACER=y
-CONFIG_WORKQUEUE_TRACER=y
 CONFIG_FTRACE_SYSCALLS=y
-CONFIG_KMEMTRACE=y
 CONFIG_FTRACE_MCOUNT_RECORD=y
 # CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
@@ -4227,6 +4193,7 @@ CONFIG_FUNCTION_TRACER=y
 CONFIG_STACK_TRACER=y
 
 CONFIG_KPROBES=y
+CONFIG_JUMP_LABEL=y
 CONFIG_OPTPROBES=y
 
 # CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
@@ -4266,7 +4233,6 @@ CONFIG_AUXDISPLAY=y
 
 CONFIG_UIO=m
 CONFIG_UIO_CIF=m
-CONFIG_UIO_SMX=m
 # CONFIG_UIO_PDRV is not set
 # CONFIG_UIO_PDRV_GENIRQ is not set
 CONFIG_UIO_AEC=m
@@ -4280,20 +4246,14 @@ CONFIG_UIO_PCI_GENERIC=m
 # LIRC
 CONFIG_LIRC_STAGING=y
 CONFIG_LIRC_BT829=m
-CONFIG_LIRC_ENE0100=m
-CONFIG_LIRC_I2C=m
 CONFIG_LIRC_IGORPLUGUSB=m
 CONFIG_LIRC_IMON=m
-CONFIG_LIRC_IT87=m
-CONFIG_LIRC_ITE8709=m
-CONFIG_LIRC_MCEUSB=m
 CONFIG_LIRC_ZILOG=m
 CONFIG_LIRC_PARALLEL=m
 CONFIG_LIRC_SERIAL=m
 CONFIG_LIRC_SERIAL_TRANSMITTER=y
 CONFIG_LIRC_SASEM=m
 CONFIG_LIRC_SIR=m
-CONFIG_LIRC_STREAMZAP=m
 CONFIG_LIRC_TTUSBIR=m
 
 # CONFIG_SAMPLES is not set
@@ -4318,7 +4278,6 @@ CONFIG_RESOURCE_COUNTERS=y
 
 #FIXME: x86 generic?
 CONFIG_LEDS_CLEVO_MAIL=m
-CONFIG_I8K=m
 CONFIG_INPUT_APANEL=m
 
 # CONFIG_INTEL_MENLOW is not set
@@ -4369,7 +4328,6 @@ CONFIG_NET_SCH_MULTIQ=m
 CONFIG_NET_ACT_SKBEDIT=m
 
 CONFIG_PHONET=m
-# CONFIG_PHONET_PIPECTRLR is not set
 
 CONFIG_ICS932S401=m
 # CONFIG_C2PORT is not set
@@ -4394,12 +4352,9 @@ CONFIG_USB_HWA_HCD=m
 CONFIG_UWB=m
 CONFIG_UWB_HWA=m
 CONFIG_UWB_WHCI=m
-CONFIG_UWB_WLP=m
 CONFIG_UWB_I1480U=m
-CONFIG_UWB_I1480U_WLP=m
 
 CONFIG_STAGING=y
-# CONFIG_STAGING_EXCLUDE_BUILD is not set
 # CONFIG_ET131X is not set
 # CONFIG_SLICOSS is not set
 # CONFIG_VIDEO_TM6000 is not set
@@ -4407,31 +4362,20 @@ CONFIG_STAGING=y
 # CONFIG_WLAGS49_H25 is not set
 # CONFIG_VIDEO_DT3155 is not set
 # CONFIG_TI_ST is not set
-# CONFIG_ST_BT is not set
 # CONFIG_FB_XGI is not set
 # CONFIG_VIDEO_GO7007 is not set
-# CONFIG_USB_IP_COMMON is not set
 # CONFIG_DT3155 is not set
 # CONFIG_W35UND is not set
 # CONFIG_PRISM2_USB is not set
 # CONFIG_ECHO is not set
 CONFIG_USB_ATMEL=m
-# CONFIG_POCH is not set
-# CONFIG_OTUS is not set
-# CONFIG_RT2860 is not set
-# CONFIG_RT2870 is not set
 # CONFIG_COMEDI is not set
 # CONFIG_ASUS_OLED is not set
 # CONFIG_PANEL is not set
-# CONFIG_ALTERA_PCIE_CHDMA is not set
-# CONFIG_INPUT_MIMIO is not set
 # CONFIG_TRANZPORT is not set
 # CONFIG_POHMELFS is not set
-# CONFIG_B3DFG is not set
 # CONFIG_IDE_PHISON is not set
-# CONFIG_PLAN9AUTH is not set
 # CONFIG_LINE6_USB is not set
-# CONFIG_RTL8192SU is not set
 # CONFIG_IIO is not set
 # CONFIG_VME_BUS is not set
 # CONFIG_RAR_REGISTER is not set
@@ -4443,7 +4387,6 @@ CONFIG_USB_ATMEL=m
 # CONFIG_HYPERV is not set
 # CONFIG_R8187SE is not set
 # CONFIG_RTL8192U is not set
-# CONFIG_RAMZSWAP is not set
 # CONFIG_BATMAN_ADV is not set
 # CONFIG_FB_SM7XX is not set
 # CONFIG_SPECTRA is not set
@@ -4451,7 +4394,6 @@ CONFIG_USB_ATMEL=m
 # CONFIG_EASYCAP is not set
 # CONFIG_SOLO6X10 is not set
 # CONFIG_ACPI_QUICKSTART is not set
-# CONFIG_BRCM80211 is not set
 # CONFIG_R8712U is not set
 # CONFIG_ATH6K_LEGACY is not set
 # CONFIG_USB_ENESTORAGE is not set
@@ -4476,10 +4418,8 @@ CONFIG_USB_ATMEL=m
 #
 
 # CONFIG_DEBUG_VIRTUAL is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FUNCTION_GRAPH_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
 CONFIG_EARLY_PRINTK_DBGP=y
 
 CONFIG_SECURITYFS=y
@@ -4502,8 +4442,6 @@ CONFIG_LSM_MMAP_MIN_ADDR=65536
 
 # CONFIG_PAGE_POISONING is not set
 
-CONFIG_SLOW_WORK=y
-CONFIG_SLOW_WORK_DEBUG=y
 
 # CONFIG_CRASH_DUMP is not set
 # CONFIG_CRASH is not set
@@ -4512,7 +4450,6 @@ CONFIG_STRIP_ASM_SYMS=y
 
 # CONFIG_RCU_FANOUT_EXACT is not set
 CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_SRCU_SYNCHRONIZE_DELAY=10
 CONFIG_RCU_CPU_STALL_TIMEOUT=60
 
 CONFIG_KSM=y
@@ -4556,7 +4493,6 @@ CONFIG_FB_UDL=m
 # from getting useful bug-reports makes it worth leaving them on.
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_HIGHMEM=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
 CONFIG_BOOT_PRINTK_DELAY=y
 CONFIG_DEBUG_LIST=y
 CONFIG_DEBUG_SHIRQ=y
@@ -4564,13 +4500,10 @@ CONFIG_DEBUG_DEVRES=y
 CONFIG_DEBUG_RODATA_TEST=y
 CONFIG_DEBUG_NX_TEST=m
 CONFIG_DEBUG_BOOT_PARAMS=y
-CONFIG_DETECT_SOFTLOCKUP=y
 CONFIG_LOCKUP_DETECTOR=y
 # CONFIG_DEBUG_INFO_REDUCED is not set
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 # CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
-# CONFIG_DETECT_HUNG_TASK is not set
-# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
 CONFIG_ATOMIC64_SELFTEST=y
 
 CONFIG_MEMORY_FAILURE=y
@@ -4602,18 +4535,14 @@ CONFIG_GPIO_SYSFS=y
 # CONFIG_GPIO_SCH is not set
 # CONFIG_GPIO_LANGWELL is not set
 # CONFIG_GPIO_RDC321X is not set
-# CONFIG_GPIO_BASIC_MMIO is not set
 # CONFIG_GPIO_VX855 is not set
 # CONFIG_GPIO_PCH is not set
 # CONFIG_GPIO_ML_IOH is not set
 
-CONFIG_KSYM_TRACER=y
-CONFIG_PROFILE_KSYM_TRACER=y
 CONFIG_KPROBE_EVENT=y
 
 # CONFIG_RAMOOPS is not set
 
-CONFIG_IR_CORE=m
 CONFIG_IR_ENE=m
 CONFIG_IR_STREAMZAP=m
 CONFIG_IR_WINBOND_CIR=m
@@ -4628,18 +4557,17 @@ CONFIG_SPARSE_RCU_POINTER=y
 
 # CONFIG_PM_OPP is not set
 
-CONFIG_BKL=y
 
 CONFIG_EVENT_POWER_TRACING_DEPRECATED=y
 
 # CONFIG_XZ_DEC_TEST is not set
 
-CONFIG_NFC_DEVICES=y
 CONFIG_PN544_NFC=m
+CONFIG_NFC_PN533=m
 
 CONFIG_TARGET_CORE=m
+CONFIG_ISCSI_TARGET=m
 CONFIG_LOOPBACK_TARGET=m
-# CONFIG_LOOPBACK_TARGET_CDB_DEBUG is not set
 CONFIG_TCM_IBLOCK=m
 CONFIG_TCM_FILEIO=m
 CONFIG_TCM_PSCSI=m
@@ -4661,3 +4589,6 @@ CONFIG_TEST_KSTRTOX=m
 
 # CONFIG_GOOGLE_FIRMWARE is not set
 CONFIG_INTEL_MID_PTI=m
+
+CONFIG_IOMMU_SUPPORT=y
+
diff --git a/config-nodebug b/config-nodebug
index 62650aa..084f88e 100644
--- a/config-nodebug
+++ b/config-nodebug
@@ -2,6 +2,8 @@ CONFIG_SND_VERBOSE_PRINTK=y
 CONFIG_SND_DEBUG=y
 CONFIG_SND_PCM_XRUN_DEBUG=y
 
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+
 # CONFIG_DEBUG_MUTEXES is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_DEBUG_LOCK_ALLOC is not set
@@ -70,7 +72,7 @@ CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1
 
 # CONFIG_JBD2_DEBUG is not set
 
-# CONFIG_DEBUG_CFQ_IOSCHED is not set
+# CONFIG_DEBUG_BLK_CGROUP is not set
 
 # CONFIG_DRBD_FAULT_INJECTION is not set
 
@@ -98,3 +100,8 @@ CONFIG_KDB_KEYBOARD=y
 # CONFIG_TEST_LIST_SORT is not set
 
 # CONFIG_DEBUG_SET_MODULE_RONX is not set
+
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+
diff --git a/config-powerpc-generic b/config-powerpc-generic
index e47c315..186aa54 100644
--- a/config-powerpc-generic
+++ b/config-powerpc-generic
@@ -60,6 +60,12 @@ CONFIG_FB_ATY_BACKLIGHT=y
 CONFIG_FB_RADEON_BACKLIGHT=y
 CONFIG_FB_RIVA_BACKLIGHT=y
 CONFIG_FB_NVIDIA_BACKLIGHT=y
+# FIXME: Do we care about this hardware ?
+CONFIG_FB_MB862XX=m
+CONFIG_FB_MB862XX_PCI_GDC=y
+CONFIG_FB_MB862XX_LIME=y
+CONFIG_FB_MB862XX_I2C=y
+
 
 CONFIG_SND_POWERMAC=m
 CONFIG_SND_POWERMAC_AUTO_DRC=y
@@ -327,16 +333,19 @@ CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m
 # CONFIG_MFD_88PM8607 is not set
 # CONFIG_MFD_MAX8997 is not set
 # CONFIG_MFD_TPS65910 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
 # CONFIG_MFD_WL1273_CORE is not set
 # CONFIG_XPS_USB_HCD_XILINX is not set
 # CONFIG_MMC_SDHCI_OF_ESDHC is not set
 # CONFIG_MMC_SDHCI_OF_HLWD is not set
 
 # CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_AAT2870_CORE is not set
 
 # CONFIG_GPIO_SCH is not set
 
 # CONFIG_PPC_MPC512x is not set
+# CONFIG_RTC_DRV_MPC5121 is not set
 
 CONFIG_MPC512X_DMA=m
 
@@ -355,3 +364,9 @@ CONFIG_CRYPTO_DEV_FSL_CAAM_INTC=y
 CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD=255
 CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD=2048
 CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API=m
+
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+# CONFIG_GPIO_MCP23S08 is not set
+
+# Disable btrfs until it is shown to work with 64k pages (rhbz 747079)
+# CONFIG_BTRFS_FS is not set
diff --git a/config-powerpc64 b/config-powerpc64
index 8866a53..ad3edf1 100644
--- a/config-powerpc64
+++ b/config-powerpc64
@@ -44,6 +44,7 @@ CONFIG_LPARCFG=y
 CONFIG_SERIAL_ICOM=m
 CONFIG_HVCS=m
 CONFIG_HVC_CONSOLE=y
+# CONFIG_HVC_OLD_HVSI is not set
 CONFIG_HOTPLUG_PCI=y
 CONFIG_THERM_PM72=y
 CONFIG_IBMVETH=m
@@ -107,9 +108,16 @@ CONFIG_NR_CPUS=128
 CONFIG_RTAS_PROC=y
 CONFIG_IOMMU_VMERGE=y
 CONFIG_NUMA=y
-# CONFIG_PPC_64K_PAGES is not set
+CONFIG_PPC_64K_PAGES=y
+CONFIG_PPC_SUBPAGE_PROT=y
 CONFIG_SCHED_SMT=y
 
+CONFIG_HZ=100
+CONFIG_HZ_100=y
+# CONFIG_HZ_1000 is not set
+
+CONFIG_MEMORY_HOTREMOVE=y
+
 # CONFIG_MV643XX_ETH is not set
 CONFIG_IRQSTACKS=y
 CONFIG_DEBUG_STACKOVERFLOW=y
@@ -118,7 +126,7 @@ CONFIG_DEBUG_STACKOVERFLOW=y
 CONFIG_EHEA=m
 CONFIG_INFINIBAND_EHCA=m
 
-CONFIG_HCALL_STATS=y
+# CONFIG_HCALL_STATS is not set
 
 CONFIG_XMON_DISASSEMBLY=y
 
@@ -147,7 +155,7 @@ CONFIG_EDAC_CPC925=m
 CONFIG_FRAME_WARN=2048
 
 CONFIG_PHYP_DUMP=y
-CONFIG_FORCE_MAX_ZONEORDER=13
+CONFIG_FORCE_MAX_ZONEORDER=9
 CONFIG_VIRTUALIZATION=y
 
 CONFIG_VSX=y
@@ -174,6 +182,8 @@ CONFIG_PERF_EVENTS=y
 CONFIG_EVENT_PROFILE=y
 
 CONFIG_KVM_BOOK3S_64=m
+#-- Enable _HV once publicly available POWER7 hardware can use it
+# CONFIG_KVM_BOOK3S_64_HV is not set
 # CONFIG_KVM_EXIT_TIMING is not set
 
 #-- bz#607175
@@ -181,10 +191,15 @@ CONFIG_KVM_BOOK3S_64=m
 CONFIG_PPC_SMLPAR=y
 CONFIG_CMM=y
 #-- DLPAR memory remove
-# CONFIG_SPARSEMEM_VMEMMAP is not set
+CONFIG_SPARSEMEM_VMEMMAP=y
+
+# CONFIG_COMPACTION is not set
 
 CONFIG_PSERIES_ENERGY=m
 
 CONFIG_PPC_ICSWX=y
 CONFIG_IO_EVENT_IRQ=y
 CONFIG_HW_RANDOM_AMD=m
+
+CONFIG_BPF_JIT=y
+CONFIG_CPU_FREQ_MAPLE=y
diff --git a/config-s390x b/config-s390x
index da9db13..5251b5b 100644
--- a/config-s390x
+++ b/config-s390x
@@ -236,5 +236,4 @@ CONFIG_STRICT_DEVMEM=y
 
 # CONFIG_WARN_DYNAMIC_STACK is not set
 
-CONFIG_JUMP_LABEL=y
 CONFIG_CRYPTO_GHASH_S390=m
diff --git a/config-sparc64-generic b/config-sparc64-generic
index dac8a64..d95a9b1 100644
--- a/config-sparc64-generic
+++ b/config-sparc64-generic
@@ -202,8 +202,6 @@ CONFIG_FB_XVR1000=y
 
 CONFIG_CRYPTO_DEV_NIAGARA2=y
 
-CONFIG_JUMP_LABEL=y
-
 # CONFIG_MTD_OF_PARTS is not set
 # CONFIG_MTD_PHYSMAP_OF is not set
 # CONFIG_MMC_SDHCI_OF is not set
diff --git a/config-x86-32-generic b/config-x86-32-generic
new file mode 100644
index 0000000..caeae93
--- /dev/null
+++ b/config-x86-32-generic
@@ -0,0 +1,206 @@
+# CONFIG_64BIT is not set
+
+CONFIG_X86_32_NON_STANDARD=y
+
+# CONFIG_X86_ELAN is not set
+# CONFIG_X86_NUMAQ is not set
+# CONFIG_X86_SUMMIT is not set
+CONFIG_X86_BIGSMP=y
+# CONFIG_X86_VISWS is not set
+# CONFIG_X86_RDC321X is not set
+# CONFIG_X86_ES7000 is not set
+# CONFIG_M386 is not set
+# CONFIG_M486 is not set
+# CONFIG_M586 is not set
+# CONFIG_M586TSC is not set
+# CONFIG_M586MMX is not set
+CONFIG_M686=y
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MVIAC3_2 is not set
+
+CONFIG_NR_CPUS=32
+CONFIG_X86_GENERIC=y
+# CONFIG_X86_PPRO_FENCE is not set
+
+CONFIG_TOSHIBA=m
+
+CONFIG_SONYPI=m
+CONFIG_SONYPI_COMPAT=y
+
+# CONFIG_NUMA is not set
+
+# CONFIG_NOHIGHMEM is not set
+CONFIG_HIGHMEM4G=y
+# CONFIG_HIGHMEM64G is not set
+CONFIG_HIGHMEM=y
+CONFIG_HIGHPTE=y
+
+# CONFIG_MATH_EMULATION is not set
+
+CONFIG_FB_GEODE=y
+CONFIG_FB_GEODE_LX=y
+CONFIG_FB_GEODE_GX=y
+# CONFIG_FB_GEODE_GX1 is not set
+
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GODIRECT is not set
+# CONFIG_PCI_GOMMCONFIG is not set
+CONFIG_PCI_GOANY=y
+
+# FIXME: wtf? "x86 specific drivers"
+CONFIG_PCMCIA_FDOMAIN=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_IBM_ASM=m
+
+#
+# APM (Advanced Power Management) BIOS Support
+#
+CONFIG_APM=y
+# CONFIG_APM_IGNORE_USER_SUSPEND is not set
+# CONFIG_APM_DO_ENABLE is not set
+CONFIG_APM_CPU_IDLE=y
+# CONFIG_APM_DISPLAY_BLANK is not set
+# CONFIG_APM_ALLOW_INTS is not set
+
+CONFIG_ACPI_BLACKLIST_YEAR=1999
+
+
+# CONFIG_X86_POWERNOW_K6 is not set
+CONFIG_X86_POWERNOW_K7=y
+# CONFIG_X86_GX_SUSPMOD is not set
+CONFIG_X86_SPEEDSTEP_ICH=y
+CONFIG_X86_SPEEDSTEP_SMI=y
+CONFIG_X86_SPEEDSTEP_LIB=y
+# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set
+CONFIG_X86_LONGRUN=y
+# CONFIG_X86_LONGHAUL is not set
+# CONFIG_X86_CPUFREQ_NFORCE2 is not set
+# e_powersaver is dangerous
+# CONFIG_X86_E_POWERSAVER is not set
+
+CONFIG_X86_HT=y
+CONFIG_X86_TRAMPOLINE=y
+
+
+# CONFIG_4KSTACKS is not set
+
+CONFIG_PCI_DIRECT=y
+
+# SHPC has half-arsed PCI probing, which makes it load on too many systems
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+
+CONFIG_BLK_DEV_AMD74XX=y
+
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+
+CONFIG_SCx200_ACB=m
+
+# CONFIG_X86_REBOOTFIXUPS is not set
+
+CONFIG_PC8736x_GPIO=m
+# CONFIG_NSC_GPIO is not set
+CONFIG_CS5535_GPIO=m
+CONFIG_GPIO_SCH=m
+
+CONFIG_SND_ISA=y
+CONFIG_SND_ES18XX=m
+
+CONFIG_HW_RANDOM_GEODE=m
+
+# CONFIG_SGI_IOC4 is not set
+
+CONFIG_TC1100_WMI=m
+
+CONFIG_IB700_WDT=m
+
+CONFIG_PHYSICAL_ALIGN=0x400000
+CONFIG_PHYSICAL_START=0x400000
+
+# CONFIG_KEXEC_JUMP is not set
+
+CONFIG_CRYPTO_AES_586=y
+CONFIG_CRYPTO_DEV_GEODE=m
+CONFIG_CRYPTO_TWOFISH_586=m
+
+CONFIG_VIDEO_CAFE_CCIC=m
+
+CONFIG_VMI=y
+
+CONFIG_XEN_MAX_DOMAIN_MEMORY=8
+
+CONFIG_MTD_NAND_CAFE=m
+
+# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set
+
+
+CONFIG_OLPC=y
+CONFIG_OLPC_OPENFIRMWARE=y
+CONFIG_BATTERY_OLPC=y
+CONFIG_MOUSE_PS2_OLPC=y
+CONFIG_OLPC_XO1_PM=y
+CONFIG_OLPC_XO15_SCI=y
+CONFIG_OLPC_XO1_RTC=y
+CONFIG_OLPC_XO1_SCI=y
+# staging
+# CONFIG_FB_OLPC_DCON is not set
+
+# CONFIG_SPARSE_IRQ is not set
+
+CONFIG_RCU_FANOUT=32
+
+# CONFIG_X86_ANCIENT_MCE is not set
+
+# CONFIG_X86_MRST is not set
+
+CONFIG_I2C_PXA=m
+# CONFIG_GPIO_LANGWELL is not set
+
+# CONFIG_INTEL_TXT is not set
+
+CONFIG_GEODE_WDT=m
+CONFIG_CS5535_MFGPT=m
+CONFIG_CS5535_CLOCK_EVENT_SRC=m
+
+CONFIG_LEDS_INTEL_SS4200=m
+
+CONFIG_OLPC_XO1=m
+CONFIG_XO1_RFKILL=m
+
+CONFIG_X86_32_IRIS=m
+
+
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_PHYSMAP_OF=m
+CONFIG_PROC_DEVICETREE=y
+CONFIG_SERIAL_OF_PLATFORM=m
+CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m
+# CONFIG_MMC_SDHCI_OF is not set
+
+# CONFIG_X86_INTEL_MID is not set
+
+CONFIG_MFD_CS5535=m
+
+# I2O enabled only for 32-bit x86, disabled for PAE kernel
+CONFIG_I2O=m
+CONFIG_I2O_BLOCK=m
+CONFIG_I2O_SCSI=m
+CONFIG_I2O_PROC=m
+CONFIG_I2O_CONFIG=y
+CONFIG_I2O_EXT_ADAPTEC=y
+CONFIG_I2O_CONFIG_OLD_IOCTL=y
+CONFIG_I2O_BUS=m
+
diff --git a/config-x86-generic b/config-x86-generic
index f124583..4252062 100644
--- a/config-x86-generic
+++ b/config-x86-generic
@@ -1,68 +1,30 @@
 CONFIG_UID16=y
-# CONFIG_64BIT is not set
-# CONFIG_KERNEL_LZMA is not set
 
-#
-# Processor type and features
-#
-#
-# Enable summit and co via the generic arch
-#
 CONFIG_X86_EXTENDED_PLATFORM=y
-CONFIG_X86_32_NON_STANDARD=y
-
-# CONFIG_X86_ELAN is not set
-# CONFIG_X86_NUMAQ is not set
-# CONFIG_X86_SUMMIT is not set
-CONFIG_X86_BIGSMP=y
-# CONFIG_X86_VISWS is not set
-# CONFIG_X86_RDC321X is not set
-# CONFIG_X86_ES7000 is not set
-# CONFIG_M386 is not set
-# CONFIG_M486 is not set
-# CONFIG_M586 is not set
-# CONFIG_M586TSC is not set
-# CONFIG_M586MMX is not set
-CONFIG_M686=y
-# CONFIG_MPENTIUMII is not set
-# CONFIG_MPENTIUMIII is not set
-# CONFIG_MPENTIUMM is not set
-# CONFIG_MPENTIUM4 is not set
-# CONFIG_MK6 is not set
-# CONFIG_MK7 is not set
-# CONFIG_MK8 is not set
-# CONFIG_MCRUSOE is not set
-# CONFIG_MWINCHIPC6 is not set
-# CONFIG_MWINCHIP3D is not set
-# CONFIG_MCYRIXIII is not set
-# CONFIG_MVIAC3_2 is not set
+
 CONFIG_SMP=y
-CONFIG_NR_CPUS=64
+
 CONFIG_X86_GENERIC=y
-# CONFIG_X86_PPRO_FENCE is not set
+
 CONFIG_HPET=y
 CONFIG_HPET_TIMER=y
 # CONFIG_HPET_MMAP is not set
-CONFIG_X86_MCE=y
-CONFIG_TOSHIBA=m
+
 CONFIG_I8K=m
-CONFIG_SONYPI=m
 CONFIG_SONYPI_COMPAT=y
 CONFIG_MICROCODE=m
+CONFIG_MICROCODE_INTEL=y
+CONFIG_MICROCODE_AMD=y
+
 CONFIG_X86_MSR=y
 CONFIG_X86_CPUID=y
 CONFIG_EDD=m
 # CONFIG_EDD_OFF is not set
-# CONFIG_NUMA is not set
 
-# CONFIG_NOHIGHMEM is not set
-CONFIG_HIGHMEM4G=y
-# CONFIG_HIGHMEM64G is not set
-CONFIG_HIGHMEM=y
-CONFIG_HIGHPTE=y
-
-# CONFIG_MATH_EMULATION is not set
 CONFIG_MTRR=y
+CONFIG_MTRR_SANITIZER=y
+CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1
+CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1
 CONFIG_X86_PAT=y
 CONFIG_X86_PM_TIMER=y
 
@@ -70,153 +32,79 @@ CONFIG_EFI=y
 CONFIG_EFI_VARS=y
 CONFIG_EFI_PCDP=y
 CONFIG_FB_EFI=y
+
+# FIXME: 32bit only?
 # CONFIG_FB_N411 is not set
 
 CONFIG_DMAR=y
 CONFIG_DMAR_BROKEN_GFX_WA=y
 CONFIG_DMAR_FLOPPY_WA=y
 CONFIG_DMAR_DEFAULT_ON=y
-
-CONFIG_FB_GEODE=y
-CONFIG_FB_GEODE_LX=y
-CONFIG_FB_GEODE_GX=y
-# CONFIG_FB_GEODE_GX1 is not set
-
-# CONFIG_PCI_GOBIOS is not set
-# CONFIG_PCI_GODIRECT is not set
-# CONFIG_PCI_GOMMCONFIG is not set
-CONFIG_PCI_GOANY=y
-
-#
-# x86 specific drivers
-#
-CONFIG_PCMCIA_FDOMAIN=m
-CONFIG_SCSI_FUTURE_DOMAIN=m
 CONFIG_SCSI_ADVANSYS=m
 
-CONFIG_CC_STACKPROTECTOR=y
-
 CONFIG_SECCOMP=y
 
 CONFIG_CAPI_EICON=y
 
-# I2O enabled only for 32-bit x86, disabled for PAE kernel
-CONFIG_I2O=m
-CONFIG_I2O_BLOCK=m
-CONFIG_I2O_SCSI=m
-CONFIG_I2O_PROC=m
-CONFIG_I2O_CONFIG=y
-CONFIG_I2O_EXT_ADAPTEC=y
-CONFIG_I2O_CONFIG_OLD_IOCTL=y
-CONFIG_I2O_BUS=m
-
-#
-# APM (Advanced Power Management) BIOS Support
-#
-CONFIG_APM=y
-# CONFIG_APM_IGNORE_USER_SUSPEND is not set
-# CONFIG_APM_DO_ENABLE is not set
-CONFIG_APM_CPU_IDLE=y
-# CONFIG_APM_DISPLAY_BLANK is not set
-# CONFIG_APM_ALLOW_INTS is not set
-
 #
 # Kernel debugging
 #
 CONFIG_X86_MPPARSE=y
+# CONFIG_X86_VERBOSE_BOOTUP is not set
+# CONFIG_MMIOTRACE_TEST is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+CONFIG_DEBUG_RODATA=y
+CONFIG_DEBUG_STACKOVERFLOW=y
 
 CONFIG_ACPI=y
 CONFIG_ACPI_AC=y
 # CONFIG_ACPI_ASUS is not set
 CONFIG_ACPI_PROCFS_POWER=y
-CONFIG_ACPI_SYSFS_POWER=y
 CONFIG_ACPI_BATTERY=y
-CONFIG_ACPI_BLACKLIST_YEAR=1999
 CONFIG_ACPI_BUTTON=y
 CONFIG_ACPI_CONTAINER=m
 CONFIG_ACPI_DOCK=y
 CONFIG_ACPI_FAN=y
 CONFIG_ACPI_NUMA=y
 CONFIG_ACPI_PROCESSOR=y
-CONFIG_ACPI_POWER=y
 CONFIG_ACPI_PROCFS=y
 CONFIG_ACPI_SBS=m
 CONFIG_ACPI_SLEEP=y
 CONFIG_ACPI_THERMAL=y
-CONFIG_TOPSTAR_LAPTOP=m
 CONFIG_ACPI_TOSHIBA=m
 CONFIG_ACPI_VIDEO=m
 # CONFIG_ACPI_PROC_EVENT is not set
 CONFIG_PNPACPI=y
-CONFIG_ACPI_POWER_METER=m
 CONFIG_ACPI_PROCESSOR_AGGREGATOR=m
 CONFIG_ACPI_HED=m
 CONFIG_ACPI_APEI=y
 CONFIG_ACPI_APEI_PCIEAER=y
-CONFIG_ACPI_APEI_GHES=m
+CONFIG_ACPI_APEI_GHES=y
+CONFIG_ACPI_APEI_MEMORY_FAILURE=y
 # CONFIG_ACPI_APEI_EINJ is not set
 CONFIG_ACPI_IPMI=m
 CONFIG_ACPI_CUSTOM_METHOD=m
 
-#
-# CPUFreq processor drivers
-#
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_DEBUG=y
-# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
-CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=m
-CONFIG_CPU_FREQ_GOV_USERSPACE=m
-CONFIG_CPU_FREQ_GOV_ONDEMAND=m
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
-CONFIG_CPU_FREQ_TABLE=y
-CONFIG_CPU_FREQ_STAT=m
-CONFIG_CPU_FREQ_STAT_DETAILS=y
-
 CONFIG_X86_ACPI_CPUFREQ=m
 CONFIG_X86_PCC_CPUFREQ=m
-# CONFIG_X86_POWERNOW_K6 is not set
-CONFIG_X86_POWERNOW_K7=y
 CONFIG_X86_POWERNOW_K8=m
-# CONFIG_X86_GX_SUSPMOD is not set
-# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
-CONFIG_X86_SPEEDSTEP_ICH=y
-CONFIG_X86_SPEEDSTEP_SMI=y
-CONFIG_X86_SPEEDSTEP_LIB=y
-# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set
 CONFIG_X86_P4_CLOCKMOD=m
-CONFIG_X86_LONGRUN=y
-# CONFIG_X86_LONGHAUL is not set
-# CONFIG_X86_CPUFREQ_NFORCE2 is not set
-# e_powersaver is dangerous
-# CONFIG_X86_E_POWERSAVER is not set
-
-CONFIG_X86_HT=y
-CONFIG_X86_TRAMPOLINE=y
+# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
 
 #
 # various x86 specific drivers
 #
 CONFIG_NVRAM=y
-CONFIG_IBM_ASM=m
-CONFIG_CRYPTO_TWOFISH_586=m
 CONFIG_CRYPTO_DEV_PADLOCK=m
 CONFIG_CRYPTO_DEV_PADLOCK_AES=m
 CONFIG_CRYPTO_DEV_PADLOCK_SHA=m
 
 CONFIG_GENERIC_ISA_DMA=y
-CONFIG_SCHED_SMT=y
+
 CONFIG_SUSPEND=y
 CONFIG_HIBERNATION=y
 CONFIG_PM_STD_PARTITION=""
 
-CONFIG_DEBUG_RODATA=y
-CONFIG_DEBUG_STACKOVERFLOW=y
-# CONFIG_4KSTACKS is not set
-CONFIG_DEBUG_NMI_TIMEOUT=5
-
-CONFIG_PCI_DIRECT=y
 CONFIG_PCI_MMCONFIG=y
 CONFIG_PCI_BIOS=y
 
@@ -225,8 +113,7 @@ CONFIG_HOTPLUG_PCI_COMPAQ=m
 # CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
 CONFIG_HOTPLUG_PCI_IBM=m
 # CONFIG_HOTPLUG_PCI_CPCI is not set
-# SHPC has half-arsed PCI probing, which makes it load on too many systems
-# CONFIG_HOTPLUG_PCI_SHPC is not set
+
 CONFIG_PM=y
 
 CONFIG_IPW2100=m
@@ -239,9 +126,6 @@ CONFIG_IPW2200_QOS=y
 
 CONFIG_BLK_DEV_AMD74XX=y
 
-CONFIG_I2C_ALI1535=m
-CONFIG_I2C_ALI15X3=m
-CONFIG_I2C_ALI1563=m
 CONFIG_I2C_AMD756=m
 CONFIG_I2C_AMD756_S4882=m
 CONFIG_I2C_AMD8111=m
@@ -250,45 +134,35 @@ CONFIG_I2C_ISCH=m
 CONFIG_I2C_NFORCE2=m
 CONFIG_I2C_NFORCE2_S4985=m
 CONFIG_I2C_PIIX4=m
-CONFIG_I2C_SIS5595=m
-CONFIG_I2C_SIS630=m
 CONFIG_I2C_SIS96X=m
-
 CONFIG_I2C_VIA=m
 CONFIG_I2C_VIAPRO=m
 
-CONFIG_SCx200_ACB=m
-
-# CONFIG_X86_REBOOTFIXUPS is not set
-
 CONFIG_DELL_RBU=m
 CONFIG_DCDBAS=m
 
-CONFIG_GPIO_SCH=m
-CONFIG_PC8736x_GPIO=m
-# CONFIG_NSC_GPIO is not set
-CONFIG_CS5535_GPIO=m
-
 CONFIG_EDAC=y
 # CONFIG_EDAC_DEBUG is not set
 CONFIG_EDAC_MM_EDAC=m
 CONFIG_EDAC_AMD76X=m
+CONFIG_EDAC_AMD8111=m
+CONFIG_EDAC_AMD8131=m
 CONFIG_EDAC_E7XXX=m
 CONFIG_EDAC_E752X=m
 CONFIG_EDAC_I82860=m
 CONFIG_EDAC_I82875P=m
 CONFIG_EDAC_I82975X=m
 CONFIG_EDAC_I3000=m
+CONFIG_EDAC_I3200=m
 CONFIG_EDAC_I5000=m
 CONFIG_EDAC_I5100=m
 CONFIG_EDAC_I5400=m
-CONFIG_EDAC_R82600=m
-CONFIG_EDAC_AMD8131=m
-CONFIG_EDAC_AMD8111=m
-CONFIG_EDAC_I7CORE=m
-CONFIG_EDAC_I3000=m
 CONFIG_EDAC_I7300=m
+CONFIG_EDAC_I7CORE=m
+CONFIG_EDAC_R82600=m
 CONFIG_EDAC_X38=m
+CONFIG_EDAC_MCE_INJ=m
+CONFIG_EDAC_DECODE_MCE=m
 
 CONFIG_SCHED_MC=y
 
@@ -299,83 +173,75 @@ CONFIG_TCG_INFINEON=m
 
 CONFIG_HW_RANDOM_INTEL=m
 CONFIG_HW_RANDOM_AMD=m
-CONFIG_HW_RANDOM_GEODE=m
 CONFIG_HW_RANDOM_VIA=m
 
-
 # CONFIG_COMPAT_VDSO is not set
 
-# CONFIG_SGI_IOC4 is not set
-
 CONFIG_X86_PLATFORM_DEVICES=y
+
 CONFIG_ASUS_LAPTOP=m
 CONFIG_COMPAL_LAPTOP=m
+CONFIG_DELL_LAPTOP=m
 CONFIG_EEEPC_LAPTOP=m
-CONFIG_EEEPC_WMI=m
 CONFIG_FUJITSU_LAPTOP=m
 # CONFIG_FUJITSU_LAPTOP_DEBUG is not set
 CONFIG_IDEAPAD_LAPTOP=m
 CONFIG_MSI_LAPTOP=m
+CONFIG_PANASONIC_LAPTOP=m
+CONFIG_SAMSUNG_LAPTOP=m
 CONFIG_SONY_LAPTOP=m
-CONFIG_DELL_LAPTOP=m
+CONFIG_TOPSTAR_LAPTOP=m
+
 CONFIG_ACPI_WMI=m
 CONFIG_ACER_WMI=m
 CONFIG_ACERHDF=m
-CONFIG_TC1100_WMI=m
+CONFIG_ASUS_WMI=m
+CONFIG_ASUS_NB_WMI=m
 CONFIG_HP_WMI=m
 # CONFIG_INTEL_SCU_IPC is not set
 CONFIG_DELL_WMI=m
 CONFIG_DELL_WMI_AIO=m
-CONFIG_ASUS_WMI=m
-CONFIG_ASUS_NB_WMI=m
-CONFIG_XO15_EBOOK=m
+CONFIG_EEEPC_WMI=m
 CONFIG_INTEL_OAKTRAIL=m
+CONFIG_SAMSUNG_Q10=m
+CONFIG_XO15_EBOOK=m
 
 # CONFIG_TOUCHSCREEN_INTEL_MID is not set
 
 # CONFIG_SMSC37B787_WDT is not set
 CONFIG_W83697HF_WDT=m
-CONFIG_IB700_WDT=m
 
-CONFIG_RELOCATABLE=y
-CONFIG_PHYSICAL_ALIGN=0x400000
-CONFIG_PHYSICAL_START=0x400000
 CONFIG_CRASH_DUMP=y
-# CONFIG_KEXEC_JUMP is not set
 CONFIG_PROC_VMCORE=y
 CONFIG_CRASH=m
 
-CONFIG_CRYPTO_DEV_GEODE=m
-
-CONFIG_VIDEO_CAFE_CCIC=m
-
 CONFIG_VIRTUALIZATION=y
 CONFIG_KVM=m
 CONFIG_KVM_INTEL=m
 CONFIG_KVM_AMD=m
 CONFIG_LGUEST=m
+CONFIG_LGUEST_GUEST=y
 
 CONFIG_PARAVIRT_GUEST=y
 CONFIG_PARAVIRT=y
+CONFIG_PARAVIRT_TIME_ACCOUNTING=y
 # CONFIG_PARAVIRT_DEBUG is not set
 
 # PARAVIRT_SPINLOCKS has a 5% perf hit
+# FIXME: Still true ? References?
 # CONFIG_PARAVIRT_SPINLOCKS is not set
+
 CONFIG_KVM_CLOCK=y
 CONFIG_KVM_GUEST=y
 CONFIG_KVM_MMU_AUDIT=y # default $x would be nice...
-CONFIG_LGUEST_GUEST=y
-CONFIG_VMI=y
 
 CONFIG_XEN=y
 # CONFIG_XEN_DEBUG is not set
-CONFIG_XEN_MAX_DOMAIN_MEMORY=8
 CONFIG_XEN_BALLOON=y
 CONFIG_XEN_SCRUB_PAGES=y
 CONFIG_XEN_SAVE_RESTORE=y
 CONFIG_HVC_XEN=y
 CONFIG_XEN_FBDEV_FRONTEND=y
-CONFIG_XEN_KBDDEV_FRONTEND=y
 CONFIG_XEN_BLKDEV_FRONTEND=m
 CONFIG_XEN_NETDEV_FRONTEND=m
 CONFIG_XEN_NETDEV_BACKEND=m
@@ -387,13 +253,14 @@ CONFIG_XEN_COMPAT_XENFS=y
 CONFIG_XEN_BACKEND=y
 CONFIG_XEN_BLKDEV_BACKEND=m
 CONFIG_XEN_DEBUG_FS=y
-CONFIG_XEN_PLATFORM_PCI=m
+CONFIG_XEN_PLATFORM_PCI=y
 CONFIG_XEN_GNTDEV=m
 CONFIG_INPUT_XEN_KBDDEV_FRONTEND=m
+CONFIG_XEN_SELFBALLOONING=y
+CONFIG_XEN_PCIDEV_BACKEND=m
 
 CONFIG_MTD_ESB2ROM=m
 CONFIG_MTD_CK804XROM=m
-CONFIG_MTD_NAND_CAFE=m
 
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -425,99 +292,52 @@ CONFIG_SENSORS_FAM15H_POWER=m
 CONFIG_SENSORS_ACPI_POWER=m
 
 # CONFIG_CPA_DEBUG is not set
-# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set
 
 CONFIG_HP_WATCHDOG=m
 CONFIG_NV_TCO=m
 CONFIG_SP5100_TCO=m
 
-CONFIG_OLPC=y
-CONFIG_OLPC_OPENFIRMWARE=y
-CONFIG_BATTERY_OLPC=y
-CONFIG_MOUSE_PS2_OLPC=y
-
-# staging
-# CONFIG_FB_OLPC_DCON is not set
-
 CONFIG_STRICT_DEVMEM=y
 
 # CONFIG_NO_BOOTMEM is not set
 
 # CONFIG_MEMTEST is not set
 # CONFIG_MAXSMP is not set
-CONFIG_MTRR_SANITIZER=y
-CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1
-CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1
-CONFIG_SYSPROF_TRACER=y
-
-# CONFIG_X86_VERBOSE_BOOTUP is not set
-# CONFIG_MMIOTRACE_TEST is not set
 
-# CONFIG_DEBUG_PER_CPU_MAPS is not set
 
 CONFIG_HP_ILO=m
 
 CONFIG_BACKLIGHT_APPLE=m
 
-CONFIG_OPROFILE_IBS=y
-CONFIG_MICROCODE_INTEL=y
-CONFIG_MICROCODE_AMD=y
 
 # CONFIG_X86_CHECK_BIOS_CORRUPTION is not set
-CONFIG_X86_RESERVE_LOW_64K=y
 
 # CONFIG_CMDLINE_BOOL is not set
 
-CONFIG_PANASONIC_LAPTOP=m
-
-CONFIG_X86_PTRACE_BTS=y
 
 CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
 
-CONFIG_POWER_TRACER=y
-CONFIG_HW_BRANCH_TRACER=y
-
-# CONFIG_SPARSE_IRQ is not set
-
-CONFIG_RCU_FANOUT=32
 
 # CONFIG_IOMMU_STRESS is not set
 
 CONFIG_PERF_COUNTERS=y
 CONFIG_PERF_EVENTS=y
-CONFIG_EVENT_PROFILE=y
 
+CONFIG_X86_MCE=y
 CONFIG_X86_MCE_INTEL=y
 CONFIG_X86_MCE_AMD=y
-# CONFIG_X86_ANCIENT_MCE is not set
 # CONFIG_X86_MCE_INJECT is not set
 
-# CONFIG_X86_MRST is not set
 CONFIG_SFI=y
 
-CONFIG_INPUT_WINBOND_CIR=m
 CONFIG_I2C_SCMI=m
-CONFIG_I2C_PXA=m
 CONFIG_SBC_FITPC2_WATCHDOG=m
-CONFIG_EDAC_I3200=m
-CONFIG_EDAC_DECODE_MCE=m
-
-# CONFIG_GPIO_LANGWELL is not set
-
-# CONFIG_INTEL_TXT is not set
-
-CONFIG_CS5535_MFGPT=m
-CONFIG_GEODE_WDT=m
-CONFIG_CS5535_CLOCK_EVENT_SRC=m
-
-CONFIG_LEDS_INTEL_SS4200=m
 
 CONFIG_X86_DECODER_SELFTEST=y
 
 CONFIG_ACPI_CMPC=m
 CONFIG_MSI_WMI=m
 CONFIG_TOSHIBA_BT_RFKILL=m
-CONFIG_SAMSUNG_LAPTOP=m
 
 CONFIG_VGA_SWITCHEROO=y
 CONFIG_LPC_SCH=m
@@ -526,46 +346,38 @@ CONFIG_PCI_CNB20LE_QUIRK=y
 
 CONFIG_ACPI_EC_DEBUGFS=m
 # CONFIG_ACPI_APEI_ERST_DEBUG is not set
+# CONFIG_ACPI_QUICKSTART is not set
+
 CONFIG_INTEL_IDLE=y
+
 # CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
-CONFIG_SENSORS_PKGTEMP=m
 CONFIG_F71808E_WDT=m
 CONFIG_HPWDT_NMI_DECODING=y
 # CONFIG_MFD_TPS6586X is not set
 # CONFIG_INTEL_MID_DMAC is not set
 CONFIG_PCH_DMA=m
-# CONFIG_ACPI_QUICKSTART is not set
-CONFIG_IDEAPAD_ACPI=m
 CONFIG_INTEL_IPS=m
 # CONFIG_IBM_RTL is not set
 
-CONFIG_OLPC_XO1=m
-CONFIG_XO1_RFKILL=m
 CONFIG_VIDEO_VIA_CAMERA=m
 
-CONFIG_EDAC_MCE_INJ=m
 CONFIG_IRQ_TIME_ACCOUNTING=y
 CONFIG_X86_RESERVE_LOW=64
 
 CONFIG_PCH_GBE=m
 CONFIG_PCH_PHUB=m
 
-CONFIG_JUMP_LABEL=y
-
-CONFIG_X86_32_IRIS=m
-
 CONFIG_TRANSPARENT_HUGEPAGE=y
 
 CONFIG_CRYPTO_AES_NI_INTEL=y
-CONFIG_CRYPTO_AES_586=y
-
-CONFIG_MTD_OF_PARTS=m
-CONFIG_MTD_PHYSMAP_OF=m
-CONFIG_PROC_DEVICETREE=y
-CONFIG_SERIAL_OF_PLATFORM=m
-CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m
-# CONFIG_MMC_SDHCI_OF is not set
 
 CONFIG_HP_ACCEL=m
 
 # CONFIG_RAPIDIO is not set
+
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+# CONFIG_GPIO_MCP23S08 is not set
+
+CONFIG_SCHED_SMT=y
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_RELOCATABLE=y
diff --git a/config-x86_64-generic b/config-x86_64-generic
index 306410c..693c3a8 100644
--- a/config-x86_64-generic
+++ b/config-x86_64-generic
@@ -1,241 +1,59 @@
 CONFIG_64BIT=y
-CONFIG_UID16=y
-# CONFIG_KERNEL_LZMA is not set
 
 # CONFIG_MK8 is not set
 # CONFIG_MPSC is not set
 CONFIG_GENERIC_CPU=y
-CONFIG_X86_EXTENDED_PLATFORM=y
+
 # CONFIG_X86_VSMP is not set
 # CONFIG_X86_UV is not set
-CONFIG_X86_MSR=y
-CONFIG_X86_CPUID=y
-CONFIG_MTRR=y
 CONFIG_NUMA=y
 CONFIG_K8_NUMA=y
 CONFIG_AMD_NUMA=y
 CONFIG_X86_64_ACPI_NUMA=y
 # CONFIG_NUMA_EMU is not set
+
 CONFIG_NR_CPUS=256
-CONFIG_X86_POWERNOW_K8=m
-CONFIG_X86_P4_CLOCKMOD=m
+CONFIG_PHYSICAL_START=0x1000000
+
 CONFIG_IA32_EMULATION=y
 # CONFIG_IA32_AOUT is not set
+
+CONFIG_AMD_IOMMU=y
+CONFIG_AMD_IOMMU_STATS=y
 # CONFIG_IOMMU_DEBUG is not set
-CONFIG_DEBUG_RODATA=y
-CONFIG_MICROCODE=m
 CONFIG_SWIOTLB=y
 CONFIG_CALGARY_IOMMU=y
 CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y
-CONFIG_X86_PM_TIMER=y
-CONFIG_EDD=m
-# CONFIG_EDD_OFF is not set
-CONFIG_PCI_BIOS=y
-CONFIG_PCI_MMCONFIG=y
-CONFIG_DMAR=y
-CONFIG_DMAR_BROKEN_GFX_WA=y
-CONFIG_DMAR_FLOPPY_WA=y
-CONFIG_DMAR_DEFAULT_ON=y
 
 CONFIG_KEXEC_JUMP=y
 
-CONFIG_EFI=y
-CONFIG_EFI_VARS=y
-CONFIG_EFI_PCDP=y
-CONFIG_FB_EFI=y
-
-CONFIG_SCSI_ADVANSYS=m
-
-CONFIG_SECCOMP=y
-
-CONFIG_CAPI_EICON=y
-
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_SCHED_SMT=y
-CONFIG_SUSPEND=y
-CONFIG_HIBERNATION=y
-CONFIG_PM_STD_PARTITION=""
-
-CONFIG_CPU_FREQ=y
-# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
-CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=m
-CONFIG_CPU_FREQ_GOV_USERSPACE=m
-CONFIG_CPU_FREQ_GOV_ONDEMAND=m
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
-CONFIG_CPU_FREQ_TABLE=y
-CONFIG_CPU_FREQ_DEBUG=y
-# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
-CONFIG_X86_PCC_CPUFREQ=m 
-CONFIG_X86_ACPI_CPUFREQ=m
-CONFIG_CPU_FREQ_STAT=m
-CONFIG_CPU_FREQ_STAT_DETAILS=y
-
-CONFIG_ACPI=y
-CONFIG_ACPI_AC=y
-# CONFIG_ACPI_ASUS is not set
-CONFIG_ACPI_PROCFS_POWER=y
-CONFIG_ACPI_SYSFS_POWER=y
-CONFIG_ACPI_BATTERY=y
 CONFIG_ACPI_BLACKLIST_YEAR=0
-CONFIG_ACPI_BUTTON=y
-CONFIG_ACPI_CONTAINER=m
-CONFIG_ACPI_DOCK=y
-CONFIG_ACPI_FAN=y
 CONFIG_ACPI_HOTPLUG_MEMORY=m
-CONFIG_ACPI_NUMA=y
-CONFIG_ACPI_PROCESSOR=y
-CONFIG_ACPI_PROCFS=y
-CONFIG_ACPI_SBS=m
-CONFIG_ACPI_SLEEP=y
-CONFIG_ACPI_THERMAL=y
-CONFIG_ACPI_TOSHIBA=m
-CONFIG_ACPI_POWER=y
-CONFIG_ACPI_VIDEO=m
-# CONFIG_ACPI_PROC_EVENT is not set
-CONFIG_ACPI_POWER_METER=m
-CONFIG_ACPI_PROCESSOR_AGGREGATOR=m
-CONFIG_ACPI_HED=m
-CONFIG_ACPI_APEI=y
-CONFIG_ACPI_APEI_PCIEAER=y
-CONFIG_ACPI_APEI_GHES=m
-# CONFIG_ACPI_APEI_EINJ is not set
-CONFIG_ACPI_IPMI=m
-CONFIG_ACPI_CUSTOM_METHOD=m
-
-CONFIG_X86_PLATFORM_DEVICES=y
-CONFIG_ASUS_LAPTOP=m
-CONFIG_COMPAL_LAPTOP=m
-CONFIG_FUJITSU_LAPTOP=m
-# CONFIG_FUJITSU_LAPTOP_DEBUG is not set
-CONFIG_MSI_LAPTOP=m
-CONFIG_SONY_LAPTOP=m
-CONFIG_SONYPI_COMPAT=y
-CONFIG_EEEPC_LAPTOP=m
-CONFIG_EEEPC_WMI=m
-CONFIG_DELL_LAPTOP=m
-CONFIG_ACPI_WMI=m
-CONFIG_ACER_WMI=m
-CONFIG_ACERHDF=m
-CONFIG_HP_WMI=m
-CONFIG_DELL_WMI=m
-CONFIG_DELL_WMI_AIO=m
-CONFIG_ASUS_WMI=m
-CONFIG_ASUS_NB_WMI=m
-# CONFIG_XO15_EBOOK is not set
-CONFIG_INTEL_OAKTRAIL=m
 
 # CONFIG_INTEL_SCU_IPC is not set
 
-# CONFIG_TOUCHSCREEN_INTEL_MID is not set
-
-CONFIG_THINKPAD_ACPI=m
-# CONFIG_THINKPAD_ACPI_DEBUG is not set
-# CONFIG_THINKPAD_ACPI_DEBUGFACILITIES is not set
-CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y
-CONFIG_THINKPAD_ACPI_VIDEO=y
-CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y
-# CONFIG_THINKPAD_ACPI_UNSAFE_LEDS is not set
-
-CONFIG_HOTPLUG_PCI=y
-CONFIG_HOTPLUG_PCI_COMPAQ=m
-# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
-CONFIG_HOTPLUG_PCI_IBM=m
-# CONFIG_HOTPLUG_PCI_CPCI is not set
 # SHPC has half-arsed PCI probing, which makes it load on too many systems
 CONFIG_HOTPLUG_PCI_SHPC=m
 
-CONFIG_HPET=y
-# CONFIG_HPET_MMAP is not set
-CONFIG_PM=y
-
-CONFIG_IPW2100=m
-CONFIG_IPW2100_MONITOR=y
-CONFIG_IPW2200=m
-CONFIG_IPW2200_MONITOR=y
-CONFIG_IPW2200_RADIOTAP=y
-CONFIG_IPW2200_PROMISCUOUS=y
-CONFIG_IPW2200_QOS=y
-
 CONFIG_PNP=y
-CONFIG_PNPACPI=y
 
+# Really ? not 32bit only ?
 CONFIG_BLK_DEV_AMD74XX=y
-CONFIG_CRYPTO_DEV_PADLOCK=m
-CONFIG_CRYPTO_DEV_PADLOCK_AES=m
-CONFIG_CRYPTO_DEV_PADLOCK_SHA=m
 
 CONFIG_CRYPTO_AES_X86_64=y
-CONFIG_CRYPTO_AES_NI_INTEL=y
-
 CONFIG_CRYPTO_TWOFISH_X86_64=m
 CONFIG_CRYPTO_SALSA20_X86_64=m
-
-CONFIG_X86_MCE=y
-CONFIG_X86_MCE_INTEL=y
-CONFIG_X86_MCE_AMD=y
+CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m
 
 # CONFIG_I2C_ALI1535 is not set
 # CONFIG_I2C_ALI1563 is not set
 # CONFIG_I2C_ALI15X3 is not set
-CONFIG_I2C_AMD756=m
-CONFIG_I2C_AMD756_S4882=m
-CONFIG_I2C_AMD8111=m
-CONFIG_I2C_I801=m
-CONFIG_I2C_ISCH=m
-CONFIG_I2C_NFORCE2_S4985=m
-CONFIG_I2C_PIIX4=m
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 
-CONFIG_I2C_SIS96X=m
-CONFIG_I2C_VIA=m
-CONFIG_I2C_VIAPRO=m
-
-CONFIG_DELL_RBU=m
-CONFIG_DCDBAS=m
-
-CONFIG_NVRAM=y
-
-CONFIG_EDAC=y
-# CONFIG_EDAC_DEBUG is not set
-CONFIG_EDAC_MM_EDAC=m
-CONFIG_EDAC_AMD76X=m
-CONFIG_EDAC_E7XXX=m
-CONFIG_EDAC_E752X=m
-CONFIG_EDAC_I5000=m
-CONFIG_EDAC_I5100=m
-CONFIG_EDAC_I5400=m
-CONFIG_EDAC_I82875P=m
-CONFIG_EDAC_I82860=m
-CONFIG_EDAC_I82975X=m
-CONFIG_EDAC_R82600=m
-CONFIG_EDAC_AMD8131=m
-CONFIG_EDAC_AMD8111=m
 CONFIG_EDAC_AMD64=m
 # CONFIG_EDAC_AMD64_ERROR_INJECTION is not set
-CONFIG_EDAC_DECODE_MCE=m
-CONFIG_EDAC_I7CORE=m
-CONFIG_EDAC_I3000=m
-CONFIG_EDAC_I7300=m
-CONFIG_EDAC_X38=m
-
-CONFIG_SCHED_MC=y
-
-CONFIG_TCG_INFINEON=m
 
-CONFIG_HW_RANDOM_INTEL=m
-CONFIG_HW_RANDOM_AMD=m
-CONFIG_HW_RANDOM_VIA=m
-
-# CONFIG_HW_RANDOM_GEODE is not set
-
-
-CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_DEBUG_NMI_TIMEOUT=5
-
-CONFIG_GPIO_SCH=m
 # CONFIG_PC8736x_GPIO is not set
 
 # CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -254,223 +72,46 @@ CONFIG_MEMORY_HOTREMOVE=y
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_CS5535 is not set
 
-CONFIG_CC_STACKPROTECTOR=y
-
 CONFIG_SGI_IOC4=m
 CONFIG_SGI_XP=m
 CONFIG_SGI_GRU=m
 # CONFIG_SGI_GRU_DEBUG is not set
 
-# CONFIG_SMSC37B787_WDT is not set
-CONFIG_W83697HF_WDT=m
-
 # CONFIG_VIDEO_CAFE_CCIC is not set
 
-CONFIG_MTD_ESB2ROM=m
-CONFIG_MTD_CK804XROM=m
-
-CONFIG_RELOCATABLE=y
-CONFIG_MACINTOSH_DRIVERS=y
-
-CONFIG_CRASH_DUMP=y
-CONFIG_PHYSICAL_START=0x1000000
-CONFIG_PROC_VMCORE=y
-CONFIG_CRASH=m
-
-CONFIG_DMIID=y
-CONFIG_DMI_SYSFS=y
-
-CONFIG_ISCSI_IBFT_FIND=y
-CONFIG_ISCSI_IBFT=m
-
-
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_CPU_IDLE=y
-# CONFIG_CPU_IDLE_GOV_LADDER is not set
-CONFIG_CPU_IDLE_GOV_MENU=y
-
-CONFIG_VIRTUALIZATION=y
-CONFIG_KVM=m
-CONFIG_KVM_INTEL=m
-CONFIG_KVM_AMD=m
-
-CONFIG_PARAVIRT_GUEST=y
-CONFIG_PARAVIRT=y
-# CONFIG_PARAVIRT_DEBUG is not set
-# PARAVIRT_SPINLOCKS has a 5% perf hit
-# CONFIG_PARAVIRT_SPINLOCKS is not set
-CONFIG_KVM_CLOCK=y
-CONFIG_KVM_GUEST=y
-CONFIG_KVM_MMU_AUDIT=y
-
-CONFIG_XEN=y
-# CONFIG_XEN_DEBUG is not set
 CONFIG_XEN_MAX_DOMAIN_MEMORY=32
-CONFIG_XEN_BALLOON=y
-CONFIG_XEN_SCRUB_PAGES=y
-CONFIG_XEN_SAVE_RESTORE=y
-CONFIG_HVC_XEN=y
-CONFIG_XEN_FBDEV_FRONTEND=y
-CONFIG_XEN_KBDDEV_FRONTEND=y
-CONFIG_XEN_BLKDEV_FRONTEND=m
-CONFIG_XEN_NETDEV_FRONTEND=m
-CONFIG_XEN_NETDEV_BACKEND=m
-CONFIG_XEN_WDT=m
-CONFIG_XEN_GRANT_DEV_ALLOC=m
-CONFIG_XEN_PCIDEV_FRONTEND=m
-CONFIG_XENFS=m
-CONFIG_XEN_COMPAT_XENFS=y
+# CONFIG_XEN_BALLOON_MEMORY_HOTPLUG is not set
 CONFIG_XEN_DEV_EVTCHN=m
 CONFIG_XEN_SYS_HYPERVISOR=y
-CONFIG_XEN_BACKEND=y
-CONFIG_XEN_BLKDEV_BACKEND=m
-CONFIG_XEN_GNTDEV=m
-CONFIG_XEN_DEBUG_FS=y
-CONFIG_XEN_PLATFORM_PCI=m
-CONFIG_INPUT_XEN_KBDDEV_FRONTEND=m
-
-CONFIG_DMADEVICES=y
-CONFIG_INTEL_IOATDMA=m
 
-CONFIG_SENSORS_I5K_AMB=m
-CONFIG_SENSORS_FAM15H_POWER=m
-CONFIG_SENSORS_ACPI_POWER=m
-
-# CONFIG_COMPAT_VDSO is not set
 CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
-# CONFIG_DEBUG_PER_CPU_MAPS is not set
-# CONFIG_CPA_DEBUG is not set
-
-CONFIG_HP_WATCHDOG=m
-CONFIG_NV_TCO=m
-CONFIG_SP5100_TCO=m
 
 CONFIG_FRAME_WARN=2048
 
 CONFIG_NODES_SHIFT=9
-CONFIG_X86_PAT=y
-# FIXME: These should be 32bit only
-# CONFIG_FB_N411 is not set
-CONFIG_STRICT_DEVMEM=y
 
 CONFIG_DIRECT_GBPAGES=y
 
-# CONFIG_NO_BOOTMEM is not set
-
-# CONFIG_MEMTEST is not set
-CONFIG_AMD_IOMMU=y
-CONFIG_AMD_IOMMU_STATS=y
-# CONFIG_MAXSMP is not set
-CONFIG_MTRR_SANITIZER=y
-CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1
-CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1
-CONFIG_SYSPROF_TRACER=y
-# CONFIG_X86_VERBOSE_BOOTUP is not set
-# CONFIG_MMIOTRACE_TEST is not set
-
 CONFIG_X86_MPPARSE=y
 
-CONFIG_BACKLIGHT_APPLE=m
-
-CONFIG_OPROFILE_IBS=y
-CONFIG_MICROCODE_INTEL=y
-CONFIG_MICROCODE_AMD=y
-
-# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set
-CONFIG_X86_RESERVE_LOW_64K=y
-
-# CONFIG_CMDLINE_BOOL is not set
-
-CONFIG_PANASONIC_LAPTOP=m
-
-CONFIG_X86_PTRACE_BTS=y
-
 CONFIG_I7300_IDLE=m
 CONFIG_INTR_REMAP=y
 
-CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
-
-CONFIG_POWER_TRACER=y
-CONFIG_HW_BRANCH_TRACER=y
-
 CONFIG_X86_X2APIC=y
 CONFIG_SPARSE_IRQ=y
 
 CONFIG_RCU_FANOUT=64
 
-# CONFIG_IOMMU_STRESS is not set
-
-CONFIG_PERF_COUNTERS=y
-CONFIG_PERF_EVENTS=y
-CONFIG_EVENT_PROFILE=y
-
-# CONFIG_X86_MCE_INJECT is not set
-
-CONFIG_SFI=y
-CONFIG_INPUT_WINBOND_CIR=m
-CONFIG_I2C_SCMI=m
-CONFIG_SBC_FITPC2_WATCHDOG=m
-CONFIG_EDAC_I3200=m
-CONFIG_TOPSTAR_LAPTOP=m
 CONFIG_INTEL_TXT=y
+
 CONFIG_GPIO_LANGWELL=y
 
 CONFIG_FUNCTION_GRAPH_TRACER=y
 
-CONFIG_ACPI_CMPC=m
-CONFIG_MSI_WMI=m
-CONFIG_TOSHIBA_BT_RFKILL=m
-CONFIG_SAMSUNG_LAPTOP=m
-
-CONFIG_CS5535_MFGPT=m
-CONFIG_GEODE_WDT=m
-CONFIG_CS5535_CLOCK_EVENT_SRC=m
-
-CONFIG_X86_DECODER_SELFTEST=y
-
-CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m
-
-CONFIG_VGA_SWITCHEROO=y
-CONFIG_LPC_SCH=m
-
 CONFIG_I7300_IDLE=m
 
-CONFIG_PCI_CNB20LE_QUIRK=y
-
-CONFIG_ACPI_EC_DEBUGFS=m
-# CONFIG_ACPI_APEI_ERST_DEBUG is not set
-CONFIG_INTEL_IDLE=y
-# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
-CONFIG_SENSORS_PKGTEMP=m
-CONFIG_F71808E_WDT=m
-CONFIG_HPWDT_NMI_DECODING=y
-# CONFIG_MFD_TPS6586X is not set
-# CONFIG_INTEL_MID_DMAC is not set
-CONFIG_PCH_DMA=m
-# CONFIG_ACPI_QUICKSTART is not set
-CONFIG_IDEAPAD_ACPI=m
-CONFIG_INTEL_IPS=m
-CONFIG_IDEAPAD_LAPTOP=m
-# CONFIG_IBM_RTL is not set
-
-CONFIG_EDAC_MCE_INJ=m
-CONFIG_IRQ_TIME_ACCOUNTING=y
-CONFIG_X86_RESERVE_LOW=64
-
-CONFIG_PCH_GBE=m
-CONFIG_PCH_PHUB=m
-
-CONFIG_VIDEO_VIA_CAMERA=m
-
-CONFIG_JUMP_LABEL=y
-
-CONFIG_HP_ILO=m
-
-CONFIG_TRANSPARENT_HUGEPAGE=y
-
-CONFIG_HP_ACCEL=m
+CONFIG_BPF_JIT=y
 
-# CONFIG_RAPIDIO is not set
+# Should be 32bit only, but lacks KConfig depends
+# CONFIG_XO15_EBOOK is not set
 
-CONFIG_BPF_JIT=y
diff --git a/dmar-disable-when-ricoh-multifunction.patch b/dmar-disable-when-ricoh-multifunction.patch
index 120730f..a452861 100644
--- a/dmar-disable-when-ricoh-multifunction.patch
+++ b/dmar-disable-when-ricoh-multifunction.patch
@@ -9,8 +9,8 @@ Subject: [PATCH] dmar: disable if ricoh multifunction detected
 
 diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
 index 4789f8e..5923914 100644
---- a/drivers/pci/intel-iommu.c
-+++ b/drivers/pci/intel-iommu.c
+--- a/drivers/iommu/intel-iommu.c
++++ b/drivers/iommu/intel-iommu.c
 @@ -3784,6 +3784,16 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_g
  DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
  DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
diff --git a/drm-i915-fbc-stfu.patch b/drm-i915-fbc-stfu.patch
new file mode 100644
index 0000000..9240387
--- /dev/null
+++ b/drm-i915-fbc-stfu.patch
@@ -0,0 +1,102 @@
+From c5d1455d9340c63e5c5d987e2d816e77538caa90 Mon Sep 17 00:00:00 2001
+From: Adam Jackson <ajax at redhat.com>
+Date: Tue, 13 Sep 2011 12:07:37 -0400
+Subject: [PATCH] drm/i915: Shut the fbc messages up
+
+FB compression enable/disable fires on pretty much every pageflip now,
+which is just uncredibly excessive.  Hush that noise.
+
+Signed-off-by: Adam Jackson <ajax at redhat.com>
+---
+ drivers/gpu/drm/i915/intel_display.c |   19 -------------------
+ 1 files changed, 0 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
+index 56a8554..a6d14eb 100644
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -1474,8 +1474,6 @@ static void i8xx_disable_fbc(struct drm_device *dev)
+ 		DRM_DEBUG_KMS("FBC idle timed out\n");
+ 		return;
+ 	}
+-
+-	DRM_DEBUG_KMS("disabled FBC\n");
+ }
+ 
+ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+@@ -1516,9 +1514,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+ 	fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
+ 	fbc_ctl |= obj->fence_reg;
+ 	I915_WRITE(FBC_CONTROL, fbc_ctl);
+-
+-	DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ",
+-		      cfb_pitch, crtc->y, intel_crtc->plane);
+ }
+ 
+ static bool i8xx_fbc_enabled(struct drm_device *dev)
+@@ -1551,8 +1546,6 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+ 
+ 	/* enable it... */
+ 	I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN);
+-
+-	DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
+ }
+ 
+ static void g4x_disable_fbc(struct drm_device *dev)
+@@ -1565,8 +1558,6 @@ static void g4x_disable_fbc(struct drm_device *dev)
+ 	if (dpfc_ctl & DPFC_CTL_EN) {
+ 		dpfc_ctl &= ~DPFC_CTL_EN;
+ 		I915_WRITE(DPFC_CONTROL, dpfc_ctl);
+-
+-		DRM_DEBUG_KMS("disabled FBC\n");
+ 	}
+ }
+ 
+@@ -1631,8 +1622,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+ 		I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
+ 		sandybridge_blit_fbc_update(dev);
+ 	}
+-
+-	DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
+ }
+ 
+ static void ironlake_disable_fbc(struct drm_device *dev)
+@@ -1645,8 +1634,6 @@ static void ironlake_disable_fbc(struct drm_device *dev)
+ 	if (dpfc_ctl & DPFC_CTL_EN) {
+ 		dpfc_ctl &= ~DPFC_CTL_EN;
+ 		I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+-
+-		DRM_DEBUG_KMS("disabled FBC\n");
+ 	}
+ }
+ 
+@@ -1701,8 +1688,6 @@ static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
+ 	if (dev_priv->fbc_work == NULL)
+ 		return;
+ 
+-	DRM_DEBUG_KMS("cancelling pending FBC enable\n");
+-
+ 	/* Synchronisation is provided by struct_mutex and checking of
+ 	 * dev_priv->fbc_work, so we can perform the cancellation
+ 	 * entirely asynchronously.
+@@ -1743,8 +1728,6 @@ static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+ 
+ 	dev_priv->fbc_work = work;
+ 
+-	DRM_DEBUG_KMS("scheduling delayed FBC enable\n");
+-
+ 	/* Delay the actual enabling to let pageflipping cease and the
+ 	 * display to settle before starting the compression. Note that
+ 	 * this delay also serves a second purpose: it allows for a
+@@ -1800,8 +1783,6 @@ static void intel_update_fbc(struct drm_device *dev)
+ 	struct drm_i915_gem_object *obj;
+ 	int enable_fbc;
+ 
+-	DRM_DEBUG_KMS("\n");
+-
+ 	if (!i915_powersave)
+ 		return;
+ 
+-- 
+1.7.6
+
diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch
index 651cc4a..1e7c927 100644
--- a/drm-nouveau-updates.patch
+++ b/drm-nouveau-updates.patch
@@ -1,460 +1,8536 @@
- drivers/gpu/drm/nouveau/nouveau_drv.c   |   11 ++-
- drivers/gpu/drm/nouveau/nouveau_drv.h   |    3 +-
- drivers/gpu/drm/nouveau/nouveau_state.c |    4 +-
- drivers/gpu/drm/nouveau/nv04_graph.c    |   22 ++----
- drivers/gpu/drm/nouveau/nv10_graph.c    |   15 +++--
- drivers/gpu/drm/nouveau/nv20_graph.c    |   11 ++-
- drivers/gpu/drm/nouveau/nv40_graph.c    |  112 ++++++-------------------------
- drivers/gpu/drm/nouveau/nv40_mpeg.c     |    2 +-
- drivers/gpu/drm/nouveau/nv50_graph.c    |    9 ++-
- drivers/gpu/drm/nouveau/nv50_mpeg.c     |    2 +-
- drivers/gpu/drm/nouveau/nv84_crypt.c    |    2 +-
- drivers/gpu/drm/nouveau/nva3_copy.c     |    2 +-
- drivers/gpu/drm/nouveau/nvc0_copy.c     |    2 +-
- drivers/gpu/drm/nouveau/nvc0_graph.c    |    2 +-
- 14 files changed, 68 insertions(+), 131 deletions(-)
-
-diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
-index 02c6f37..4e1a360 100644
---- a/drivers/gpu/drm/nouveau/nouveau_drv.c
-+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
-@@ -210,10 +210,13 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
- 	pfifo->unload_context(dev);
- 
- 	for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
--		if (dev_priv->eng[e]) {
--			ret = dev_priv->eng[e]->fini(dev, e);
--			if (ret)
--				goto out_abort;
-+		if (!dev_priv->eng[e])
-+			continue;
-+
-+		ret = dev_priv->eng[e]->fini(dev, e, true);
-+		if (ret) {
-+			NV_ERROR(dev, "... engine %d failed: %d\n", i, ret);
-+			goto out_abort;
- 		}
- 	}
- 
-diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
-index 9c56331..82d6295 100644
---- a/drivers/gpu/drm/nouveau/nouveau_drv.h
-+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
-@@ -297,7 +297,7 @@ struct nouveau_channel {
- struct nouveau_exec_engine {
- 	void (*destroy)(struct drm_device *, int engine);
- 	int  (*init)(struct drm_device *, int engine);
--	int  (*fini)(struct drm_device *, int engine);
-+	int  (*fini)(struct drm_device *, int engine, bool suspend);
- 	int  (*context_new)(struct nouveau_channel *, int engine);
- 	void (*context_del)(struct nouveau_channel *, int engine);
- 	int  (*object_new)(struct nouveau_channel *, int engine,
-@@ -1120,7 +1120,6 @@ extern int  nvc0_fifo_unload_context(struct drm_device *);
- 
- /* nv04_graph.c */
- extern int  nv04_graph_create(struct drm_device *);
--extern void nv04_graph_fifo_access(struct drm_device *, bool);
- extern int  nv04_graph_object_new(struct nouveau_channel *, int, u32, u16);
- extern int  nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
- 				      u32 class, u32 mthd, u32 data);
-diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
-index 731acea..e65e71b 100644
---- a/drivers/gpu/drm/nouveau/nouveau_state.c
-+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
-@@ -682,7 +682,7 @@ out_engine:
- 		for (e = e - 1; e >= 0; e--) {
- 			if (!dev_priv->eng[e])
- 				continue;
--			dev_priv->eng[e]->fini(dev, e);
-+			dev_priv->eng[e]->fini(dev, e, false);
- 			dev_priv->eng[e]->destroy(dev,e );
- 		}
- 	}
-@@ -727,7 +727,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
- 		engine->fifo.takedown(dev);
- 		for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
- 			if (dev_priv->eng[e]) {
--				dev_priv->eng[e]->fini(dev, e);
-+				dev_priv->eng[e]->fini(dev, e, false);
- 				dev_priv->eng[e]->destroy(dev,e );
- 			}
- 		}
-diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
-index 3626ee7..dbdea8e 100644
---- a/drivers/gpu/drm/nouveau/nv04_graph.c
-+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
-@@ -450,13 +450,13 @@ nv04_graph_context_del(struct nouveau_channel *chan, int engine)
- 	unsigned long flags;
- 
- 	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
--	nv04_graph_fifo_access(dev, false);
-+	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
+index 0583677..35ef5b1 100644
+--- a/drivers/gpu/drm/nouveau/Makefile
++++ b/drivers/gpu/drm/nouveau/Makefile
+@@ -21,16 +21,17 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
+              nv40_grctx.o nv50_grctx.o nvc0_grctx.o \
+              nv84_crypt.o \
+              nva3_copy.o nvc0_copy.o \
+-             nv40_mpeg.o nv50_mpeg.o \
++             nv31_mpeg.o nv50_mpeg.o \
+              nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
+-             nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \
+-             nv50_cursor.o nv50_display.o \
+              nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
+              nv04_crtc.o nv04_display.o nv04_cursor.o \
++             nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \
++             nv50_cursor.o nv50_display.o \
++             nvd0_display.o \
+              nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o \
+              nv10_gpio.o nv50_gpio.o \
+ 	     nv50_calc.o \
+-	     nv04_pm.o nv50_pm.o nva3_pm.o \
++	     nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \
+ 	     nv50_vram.o nvc0_vram.o \
+ 	     nv50_vm.o nvc0_vm.o
  
- 	/* Unload the context if it's the currently active one */
- 	if (nv04_graph_channel(dev) == chan)
- 		nv04_graph_unload_context(dev);
+diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
+index 00a55df..fa22b28 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
++++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
+@@ -37,8 +37,10 @@
+ #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_reg.h"
++#include "nouveau_encoder.h"
  
--	nv04_graph_fifo_access(dev, true);
-+	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
- 	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- 
- 	/* Free the context resources */
-@@ -538,24 +538,18 @@ nv04_graph_init(struct drm_device *dev, int engine)
+-static int nv40_get_intensity(struct backlight_device *bd)
++static int
++nv40_get_intensity(struct backlight_device *bd)
+ {
+ 	struct drm_device *dev = bl_get_data(bd);
+ 	int val = (nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK)
+@@ -47,7 +49,8 @@ static int nv40_get_intensity(struct backlight_device *bd)
+ 	return val;
  }
  
- static int
--nv04_graph_fini(struct drm_device *dev, int engine)
-+nv04_graph_fini(struct drm_device *dev, int engine, bool suspend)
+-static int nv40_set_intensity(struct backlight_device *bd)
++static int
++nv40_set_intensity(struct backlight_device *bd)
  {
-+	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-+	if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
-+		nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-+		return -EBUSY;
-+	}
- 	nv04_graph_unload_context(dev);
- 	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
- 	return 0;
- }
+ 	struct drm_device *dev = bl_get_data(bd);
+ 	int val = bd->props.brightness;
+@@ -65,30 +68,8 @@ static const struct backlight_ops nv40_bl_ops = {
+ 	.update_status = nv40_set_intensity,
+ };
  
--void
--nv04_graph_fifo_access(struct drm_device *dev, bool enabled)
+-static int nv50_get_intensity(struct backlight_device *bd)
 -{
--	if (enabled)
--		nv_wr32(dev, NV04_PGRAPH_FIFO,
--					nv_rd32(dev, NV04_PGRAPH_FIFO) | 1);
--	else
--		nv_wr32(dev, NV04_PGRAPH_FIFO,
--					nv_rd32(dev, NV04_PGRAPH_FIFO) & ~1);
+-	struct drm_device *dev = bl_get_data(bd);
+-
+-	return nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT);
 -}
 -
- static int
- nv04_graph_mthd_set_ref(struct nouveau_channel *chan,
- 			u32 class, u32 mthd, u32 data)
-diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
-index 0930c6c..7255e4a 100644
---- a/drivers/gpu/drm/nouveau/nv10_graph.c
-+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
-@@ -708,8 +708,8 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
- 		0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
- 	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
- 	nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
--	nv04_graph_fifo_access(dev, true);
--	nv04_graph_fifo_access(dev, false);
-+	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-+	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
- 
- 	/* Restore the FIFO state */
- 	for (i = 0; i < ARRAY_SIZE(fifo); i++)
-@@ -879,13 +879,13 @@ nv10_graph_context_del(struct nouveau_channel *chan, int engine)
- 	unsigned long flags;
- 
- 	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
--	nv04_graph_fifo_access(dev, false);
-+	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
- 
- 	/* Unload the context if it's the currently active one */
- 	if (nv10_graph_channel(dev) == chan)
- 		nv10_graph_unload_context(dev);
- 
--	nv04_graph_fifo_access(dev, true);
-+	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
- 	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- 
- 	/* Free the context resources */
-@@ -957,8 +957,13 @@ nv10_graph_init(struct drm_device *dev, int engine)
+-static int nv50_set_intensity(struct backlight_device *bd)
+-{
+-	struct drm_device *dev = bl_get_data(bd);
+-	int val = bd->props.brightness;
+-
+-	nv_wr32(dev, NV50_PDISPLAY_SOR_BACKLIGHT,
+-		val | NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE);
+-	return 0;
+-}
+-
+-static const struct backlight_ops nv50_bl_ops = {
+-	.options = BL_CORE_SUSPENDRESUME,
+-	.get_brightness = nv50_get_intensity,
+-	.update_status = nv50_set_intensity,
+-};
+-
+-static int nouveau_nv40_backlight_init(struct drm_connector *connector)
++static int
++nv40_backlight_init(struct drm_connector *connector)
+ {
+ 	struct drm_device *dev = connector->dev;
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+@@ -113,34 +94,129 @@ static int nouveau_nv40_backlight_init(struct drm_connector *connector)
+ 	return 0;
  }
  
- static int
--nv10_graph_fini(struct drm_device *dev, int engine)
-+nv10_graph_fini(struct drm_device *dev, int engine, bool suspend)
+-static int nouveau_nv50_backlight_init(struct drm_connector *connector)
++static int
++nv50_get_intensity(struct backlight_device *bd)
++{
++	struct nouveau_encoder *nv_encoder = bl_get_data(bd);
++	struct drm_device *dev = nv_encoder->base.base.dev;
++	int or = nv_encoder->or;
++	u32 div = 1025;
++	u32 val;
++
++	val  = nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(or));
++	val &= NV50_PDISP_SOR_PWM_CTL_VAL;
++	return ((val * 100) + (div / 2)) / div;
++}
++
++static int
++nv50_set_intensity(struct backlight_device *bd)
++{
++	struct nouveau_encoder *nv_encoder = bl_get_data(bd);
++	struct drm_device *dev = nv_encoder->base.base.dev;
++	int or = nv_encoder->or;
++	u32 div = 1025;
++	u32 val = (bd->props.brightness * div) / 100;
++
++	nv_wr32(dev, NV50_PDISP_SOR_PWM_CTL(or),
++		     NV50_PDISP_SOR_PWM_CTL_NEW | val);
++	return 0;
++}
++
++static const struct backlight_ops nv50_bl_ops = {
++	.options = BL_CORE_SUSPENDRESUME,
++	.get_brightness = nv50_get_intensity,
++	.update_status = nv50_set_intensity,
++};
++
++static int
++nva3_get_intensity(struct backlight_device *bd)
++{
++	struct nouveau_encoder *nv_encoder = bl_get_data(bd);
++	struct drm_device *dev = nv_encoder->base.base.dev;
++	int or = nv_encoder->or;
++	u32 div, val;
++
++	div  = nv_rd32(dev, NV50_PDISP_SOR_PWM_DIV(or));
++	val  = nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(or));
++	val &= NVA3_PDISP_SOR_PWM_CTL_VAL;
++	if (div && div >= val)
++		return ((val * 100) + (div / 2)) / div;
++
++	return 100;
++}
++
++static int
++nva3_set_intensity(struct backlight_device *bd)
++{
++	struct nouveau_encoder *nv_encoder = bl_get_data(bd);
++	struct drm_device *dev = nv_encoder->base.base.dev;
++	int or = nv_encoder->or;
++	u32 div, val;
++
++	div = nv_rd32(dev, NV50_PDISP_SOR_PWM_DIV(or));
++	val = (bd->props.brightness * div) / 100;
++	if (div) {
++		nv_wr32(dev, NV50_PDISP_SOR_PWM_CTL(or), val |
++			     NV50_PDISP_SOR_PWM_CTL_NEW |
++			     NVA3_PDISP_SOR_PWM_CTL_UNK);
++		return 0;
++	}
++
++	return -EINVAL;
++}
++
++static const struct backlight_ops nva3_bl_ops = {
++	.options = BL_CORE_SUSPENDRESUME,
++	.get_brightness = nva3_get_intensity,
++	.update_status = nva3_set_intensity,
++};
++
++static int
++nv50_backlight_init(struct drm_connector *connector)
  {
-+	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-+	if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
-+		nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-+		return -EBUSY;
+ 	struct drm_device *dev = connector->dev;
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nouveau_encoder *nv_encoder;
+ 	struct backlight_properties props;
+ 	struct backlight_device *bd;
++	const struct backlight_ops *ops;
++
++	nv_encoder = find_encoder(connector, OUTPUT_LVDS);
++	if (!nv_encoder) {
++		nv_encoder = find_encoder(connector, OUTPUT_DP);
++		if (!nv_encoder)
++			return -ENODEV;
 +	}
- 	nv10_graph_unload_context(dev);
- 	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
+ 
+-	if (!nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT))
++	if (!nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(nv_encoder->or)))
+ 		return 0;
+ 
++	if (dev_priv->chipset <= 0xa0 ||
++	    dev_priv->chipset == 0xaa ||
++	    dev_priv->chipset == 0xac)
++		ops = &nv50_bl_ops;
++	else
++		ops = &nva3_bl_ops;
++
+ 	memset(&props, 0, sizeof(struct backlight_properties));
+ 	props.type = BACKLIGHT_RAW;
+-	props.max_brightness = 1025;
+-	bd = backlight_device_register("nv_backlight", &connector->kdev, dev,
+-				       &nv50_bl_ops, &props);
++	props.max_brightness = 100;
++	bd = backlight_device_register("nv_backlight", &connector->kdev,
++				       nv_encoder, ops, &props);
+ 	if (IS_ERR(bd))
+ 		return PTR_ERR(bd);
+ 
+ 	dev_priv->backlight = bd;
+-	bd->props.brightness = nv50_get_intensity(bd);
++	bd->props.brightness = bd->ops->get_brightness(bd);
+ 	backlight_update_status(bd);
  	return 0;
-diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
-index affc7d7..b6cf157 100644
---- a/drivers/gpu/drm/nouveau/nv20_graph.c
-+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
-@@ -454,13 +454,13 @@ nv20_graph_context_del(struct nouveau_channel *chan, int engine)
- 	unsigned long flags;
+ }
  
- 	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
--	nv04_graph_fifo_access(dev, false);
-+	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+-int nouveau_backlight_init(struct drm_connector *connector)
++int
++nouveau_backlight_init(struct drm_device *dev)
+ {
+-	struct drm_device *dev = connector->dev;
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct drm_connector *connector;
  
- 	/* Unload the context if it's the currently active one */
- 	if (nv10_graph_channel(dev) == chan)
- 		nv20_graph_unload_context(dev);
+ #ifdef CONFIG_ACPI
+ 	if (acpi_video_backlight_support()) {
+@@ -150,21 +226,28 @@ int nouveau_backlight_init(struct drm_connector *connector)
+ 	}
+ #endif
  
--	nv04_graph_fifo_access(dev, true);
-+	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
- 	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+-	switch (dev_priv->card_type) {
+-	case NV_40:
+-		return nouveau_nv40_backlight_init(connector);
+-	case NV_50:
+-		return nouveau_nv50_backlight_init(connector);
+-	default:
+-		break;
++	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
++		if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
++		    connector->connector_type != DRM_MODE_CONNECTOR_eDP)
++			continue;
++
++		switch (dev_priv->card_type) {
++		case NV_40:
++			return nv40_backlight_init(connector);
++		case NV_50:
++			return nv50_backlight_init(connector);
++		default:
++			break;
++		}
+ 	}
  
- 	/* Free the context resources */
-@@ -654,8 +654,13 @@ nv30_graph_init(struct drm_device *dev, int engine)
++
+ 	return 0;
  }
  
- int
--nv20_graph_fini(struct drm_device *dev, int engine)
-+nv20_graph_fini(struct drm_device *dev, int engine, bool suspend)
+-void nouveau_backlight_exit(struct drm_connector *connector)
++void
++nouveau_backlight_exit(struct drm_device *dev)
  {
-+	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-+	if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
-+		nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-+		return -EBUSY;
+-	struct drm_device *dev = connector->dev;
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 
+ 	if (dev_priv->backlight) {
+diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
+index b311fab..032a820 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
++++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
+@@ -296,6 +296,11 @@ munge_reg(struct nvbios *bios, uint32_t reg)
+ 	if (dev_priv->card_type < NV_50)
+ 		return reg;
+ 
++	if (reg & 0x80000000) {
++		BUG_ON(bios->display.crtc < 0);
++		reg += bios->display.crtc * 0x800;
++	}
++
+ 	if (reg & 0x40000000) {
+ 		BUG_ON(!dcbent);
+ 
+@@ -304,7 +309,7 @@ munge_reg(struct nvbios *bios, uint32_t reg)
+ 			reg += 0x00000080;
+ 	}
+ 
+-	reg &= ~0x60000000;
++	reg &= ~0xe0000000;
+ 	return reg;
+ }
+ 
+@@ -1174,22 +1179,19 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+ 	 *
+ 	 */
+ 
+-	struct bit_displayport_encoder_table *dpe = NULL;
+ 	struct dcb_entry *dcb = bios->display.output;
+ 	struct drm_device *dev = bios->dev;
+ 	uint8_t cond = bios->data[offset + 1];
+-	int dummy;
++	uint8_t *table, *entry;
+ 
+ 	BIOSLOG(bios, "0x%04X: subop 0x%02X\n", offset, cond);
+ 
+ 	if (!iexec->execute)
+ 		return 3;
+ 
+-	dpe = nouveau_bios_dp_table(dev, dcb, &dummy);
+-	if (!dpe) {
+-		NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset);
++	table = nouveau_dp_bios_data(dev, dcb, &entry);
++	if (!table)
+ 		return 3;
+-	}
+ 
+ 	switch (cond) {
+ 	case 0:
+@@ -1203,7 +1205,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+ 		break;
+ 	case 1:
+ 	case 2:
+-		if (!(dpe->unknown & cond))
++		if (!(entry[5] & cond))
+ 			iexec->execute = false;
+ 		break;
+ 	case 5:
+@@ -3221,6 +3223,49 @@ init_8d(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+ 	return 1;
+ }
+ 
++static void
++init_gpio_unknv50(struct nvbios *bios, struct dcb_gpio_entry *gpio)
++{
++	const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
++	u32 r, s, v;
++
++	/* Not a clue, needs de-magicing */
++	r = nv50_gpio_ctl[gpio->line >> 4];
++	s = (gpio->line & 0x0f);
++	v = bios_rd32(bios, r) & ~(0x00010001 << s);
++	switch ((gpio->entry & 0x06000000) >> 25) {
++	case 1:
++		v |= (0x00000001 << s);
++		break;
++	case 2:
++		v |= (0x00010000 << s);
++		break;
++	default:
++		break;
++	}
++
++	bios_wr32(bios, r, v);
++}
++
++static void
++init_gpio_unknvd0(struct nvbios *bios, struct dcb_gpio_entry *gpio)
++{
++	u32 v, i;
++
++	v  = bios_rd32(bios, 0x00d610 + (gpio->line * 4));
++	v &= 0xffffff00;
++	v |= (gpio->entry & 0x00ff0000) >> 16;
++	bios_wr32(bios, 0x00d610 + (gpio->line * 4), v);
++
++	i = (gpio->entry & 0x1f000000) >> 24;
++	if (i) {
++		v  = bios_rd32(bios, 0x00d640 + ((i - 1) * 4));
++		v &= 0xffffff00;
++		v |= gpio->line;
++		bios_wr32(bios, 0x00d640 + ((i - 1) * 4), v);
 +	}
- 	nv20_graph_unload_context(dev);
- 	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
++}
++
+ static int
+ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+ {
+@@ -3235,7 +3280,6 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+ 
+ 	struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
+ 	struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
+-	const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
+ 	int i;
+ 
+ 	if (dev_priv->card_type < NV_50) {
+@@ -3248,33 +3292,20 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+ 
+ 	for (i = 0; i < bios->dcb.gpio.entries; i++) {
+ 		struct dcb_gpio_entry *gpio = &bios->dcb.gpio.entry[i];
+-		uint32_t r, s, v;
+ 
+ 		BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry);
+ 
+ 		BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n",
+ 			offset, gpio->tag, gpio->state_default);
+-		if (bios->execute)
+-			pgpio->set(bios->dev, gpio->tag, gpio->state_default);
+ 
+-		/* The NVIDIA binary driver doesn't appear to actually do
+-		 * any of this, my VBIOS does however.
+-		 */
+-		/* Not a clue, needs de-magicing */
+-		r = nv50_gpio_ctl[gpio->line >> 4];
+-		s = (gpio->line & 0x0f);
+-		v = bios_rd32(bios, r) & ~(0x00010001 << s);
+-		switch ((gpio->entry & 0x06000000) >> 25) {
+-		case 1:
+-			v |= (0x00000001 << s);
+-			break;
+-		case 2:
+-			v |= (0x00010000 << s);
+-			break;
+-		default:
+-			break;
+-		}
+-		bios_wr32(bios, r, v);
++		if (!bios->execute)
++			continue;
++
++		pgpio->set(bios->dev, gpio->tag, gpio->state_default);
++		if (dev_priv->card_type < NV_D0)
++			init_gpio_unknv50(bios, gpio);
++		else
++			init_gpio_unknvd0(bios, gpio);
+ 	}
+ 
+ 	return 1;
+@@ -3737,6 +3768,10 @@ parse_init_table(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+ 	int count = 0, i, ret;
+ 	uint8_t id;
+ 
++	/* catch NULL script pointers */
++	if (offset == 0)
++		return 0;
++
+ 	/*
+ 	 * Loop until INIT_DONE causes us to break out of the loop
+ 	 * (or until offset > bios length just in case... )
+@@ -4389,86 +4424,37 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b
  	return 0;
-diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
-index 5beb01b..ba14a93 100644
---- a/drivers/gpu/drm/nouveau/nv40_graph.c
-+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
-@@ -35,89 +35,6 @@ struct nv40_graph_engine {
- 	u32 grctx_size;
- };
+ }
  
--static struct nouveau_channel *
--nv40_graph_channel(struct drm_device *dev)
--{
+-static uint8_t *
+-bios_output_config_match(struct drm_device *dev, struct dcb_entry *dcbent,
+-			 uint16_t record, int record_len, int record_nr,
+-			 bool match_link)
++/* BIT 'U'/'d' table encoder subtables have hashes matching them to
++ * a particular set of encoders.
++ *
++ * This function returns true if a particular DCB entry matches.
++ */
++bool
++bios_encoder_match(struct dcb_entry *dcb, u32 hash)
+ {
 -	struct drm_nouveau_private *dev_priv = dev->dev_private;
--	struct nouveau_gpuobj *grctx;
--	uint32_t inst;
--	int i;
--
--	inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
--	if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
--		return NULL;
--	inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4;
--
--	for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
--		if (!dev_priv->channels.ptr[i])
--			continue;
--
--		grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
--		if (grctx && grctx->pinst == inst)
--			return dev_priv->channels.ptr[i];
+-	struct nvbios *bios = &dev_priv->vbios;
+-	uint32_t entry;
+-	uint16_t table;
+-	int i, v;
++	if ((hash & 0x000000f0) != (dcb->location << 4))
++		return false;
++	if ((hash & 0x0000000f) != dcb->type)
++		return false;
++	if (!(hash & (dcb->or << 16)))
++		return false;
+ 
+-	switch (dcbent->type) {
++	switch (dcb->type) {
+ 	case OUTPUT_TMDS:
+ 	case OUTPUT_LVDS:
+ 	case OUTPUT_DP:
+-		break;
+-	default:
+-		match_link = false;
+-		break;
 -	}
 -
--	return NULL;
--}
--
--static int
--nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
--{
--	uint32_t old_cp, tv = 1000, tmp;
--	int i;
--
--	old_cp = nv_rd32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER);
--	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
--
--	tmp  = nv_rd32(dev, NV40_PGRAPH_CTXCTL_0310);
--	tmp |= save ? NV40_PGRAPH_CTXCTL_0310_XFER_SAVE :
--		      NV40_PGRAPH_CTXCTL_0310_XFER_LOAD;
--	nv_wr32(dev, NV40_PGRAPH_CTXCTL_0310, tmp);
+-	for (i = 0; i < record_nr; i++, record += record_len) {
+-		table = ROM16(bios->data[record]);
+-		if (!table)
+-			continue;
+-		entry = ROM32(bios->data[table]);
 -
--	tmp  = nv_rd32(dev, NV40_PGRAPH_CTXCTL_0304);
--	tmp |= NV40_PGRAPH_CTXCTL_0304_XFER_CTX;
--	nv_wr32(dev, NV40_PGRAPH_CTXCTL_0304, tmp);
+-		if (match_link) {
+-			v = (entry & 0x00c00000) >> 22;
+-			if (!(v & dcbent->sorconf.link))
+-				continue;
++		if (hash & 0x00c00000) {
++			if (!(hash & (dcb->sorconf.link << 22)))
++				return false;
+ 		}
 -
--	nouveau_wait_for_idle(dev);
+-		v = (entry & 0x000f0000) >> 16;
+-		if (!(v & dcbent->or))
+-			continue;
 -
--	for (i = 0; i < tv; i++) {
--		if (nv_rd32(dev, NV40_PGRAPH_CTXCTL_030C) == 0)
--			break;
--	}
+-		v = (entry & 0x000000f0) >> 4;
+-		if (v != dcbent->location)
+-			continue;
 -
--	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, old_cp);
+-		v = (entry & 0x0000000f);
+-		if (v != dcbent->type)
+-			continue;
 -
--	if (i == tv) {
--		uint32_t ucstat = nv_rd32(dev, NV40_PGRAPH_CTXCTL_UCODE_STAT);
--		NV_ERROR(dev, "Failed: Instance=0x%08x Save=%d\n", inst, save);
--		NV_ERROR(dev, "IP: 0x%02x, Opcode: 0x%08x\n",
--			 ucstat >> NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT,
--			 ucstat  & NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK);
--		NV_ERROR(dev, "0x40030C = 0x%08x\n",
--			 nv_rd32(dev, NV40_PGRAPH_CTXCTL_030C));
--		return -EBUSY;
+-		return &bios->data[table];
 -	}
 -
--	return 0;
+-	return NULL;
 -}
 -
--static int
--nv40_graph_unload_context(struct drm_device *dev)
+-void *
+-nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent,
+-		      int *length)
 -{
--	uint32_t inst;
--	int ret;
--
--	inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
--	if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
--		return 0;
--	inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nvbios *bios = &dev_priv->vbios;
+-	uint8_t *table;
 -
--	ret = nv40_graph_transfer_context(dev, inst, 1);
+-	if (!bios->display.dp_table_ptr) {
+-		NV_ERROR(dev, "No pointer to DisplayPort table\n");
+-		return NULL;
+-	}
+-	table = &bios->data[bios->display.dp_table_ptr];
 -
--	nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
--	return ret;
--}
+-	if (table[0] != 0x20 && table[0] != 0x21) {
+-		NV_ERROR(dev, "DisplayPort table version 0x%02x unknown\n",
+-			 table[0]);
+-		return NULL;
++	default:
++		return true;
+ 	}
 -
- static int
- nv40_graph_context_new(struct nouveau_channel *chan, int engine)
- {
-@@ -163,16 +80,16 @@ nv40_graph_context_del(struct nouveau_channel *chan, int engine)
- 	struct nouveau_gpuobj *grctx = chan->engctx[engine];
- 	struct drm_device *dev = chan->dev;
- 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-+	u32 inst = 0x01000000 | (grctx->pinst >> 4);
- 	unsigned long flags;
+-	*length = table[4];
+-	return bios_output_config_match(dev, dcbent,
+-					bios->display.dp_table_ptr + table[1],
+-					table[2], table[3], table[0] >= 0x21);
+ }
  
- 	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
--	nv04_graph_fifo_access(dev, false);
--
--	/* Unload the context if it's the currently active one */
--	if (nv40_graph_channel(dev) == chan)
--		nv40_graph_unload_context(dev);
--
--	nv04_graph_fifo_access(dev, true);
-+	nv_mask(dev, 0x400720, 0x00000000, 0x00000001);
-+	if (nv_rd32(dev, 0x40032c) == inst)
-+		nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
-+	if (nv_rd32(dev, 0x400330) == inst)
-+		nv_mask(dev, 0x400330, 0x01000000, 0x00000000);
-+	nv_mask(dev, 0x400720, 0x00000001, 0x00000001);
- 	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+ int
+-nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
+-			       uint32_t sub, int pxclk)
++nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk,
++			       struct dcb_entry *dcbent, int crtc)
+ {
+ 	/*
+ 	 * The display script table is located by the BIT 'U' table.
+@@ -4498,7 +4484,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
+ 	uint8_t *table = &bios->data[bios->display.script_table_ptr];
+ 	uint8_t *otable = NULL;
+ 	uint16_t script;
+-	int i = 0;
++	int i;
  
- 	/* Free the context resources */
-@@ -429,9 +346,20 @@ nv40_graph_init(struct drm_device *dev, int engine)
- }
+ 	if (!bios->display.script_table_ptr) {
+ 		NV_ERROR(dev, "No pointer to output script table\n");
+@@ -4550,30 +4536,33 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
  
- static int
--nv40_graph_fini(struct drm_device *dev, int engine)
-+nv40_graph_fini(struct drm_device *dev, int engine, bool suspend)
- {
--	nv40_graph_unload_context(dev);
-+	u32 inst = nv_rd32(dev, 0x40032c);
-+	if (inst & 0x01000000) {
-+		nv_wr32(dev, 0x400720, 0x00000000);
-+		nv_wr32(dev, 0x400784, inst);
-+		nv_mask(dev, 0x400310, 0x00000020, 0x00000020);
-+		nv_mask(dev, 0x400304, 0x00000001, 0x00000001);
-+		if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000)) {
-+			u32 insn = nv_rd32(dev, 0x400308);
-+			NV_ERROR(dev, "PGRAPH: ctxprog timeout 0x%08x\n", insn);
-+		}
-+		nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
+ 	NV_DEBUG_KMS(dev, "Searching for output entry for %d %d %d\n",
+ 			dcbent->type, dcbent->location, dcbent->or);
+-	otable = bios_output_config_match(dev, dcbent, table[1] +
+-					  bios->display.script_table_ptr,
+-					  table[2], table[3], table[0] >= 0x21);
++	for (i = 0; i < table[3]; i++) {
++		otable = ROMPTR(bios, table[table[1] + (i * table[2])]);
++		if (otable && bios_encoder_match(dcbent, ROM32(otable[0])))
++			break;
 +	}
- 	return 0;
- }
++
+ 	if (!otable) {
+ 		NV_DEBUG_KMS(dev, "failed to match any output table\n");
+ 		return 1;
+ 	}
  
-diff --git a/drivers/gpu/drm/nouveau/nv40_mpeg.c b/drivers/gpu/drm/nouveau/nv40_mpeg.c
-index 6d2af29..ad03a0e 100644
---- a/drivers/gpu/drm/nouveau/nv40_mpeg.c
-+++ b/drivers/gpu/drm/nouveau/nv40_mpeg.c
-@@ -137,7 +137,7 @@ nv40_mpeg_init(struct drm_device *dev, int engine)
- }
+-	if (pxclk < -2 || pxclk > 0) {
++	if (pclk < -2 || pclk > 0) {
+ 		/* Try to find matching script table entry */
+ 		for (i = 0; i < otable[5]; i++) {
+-			if (ROM16(otable[table[4] + i*6]) == sub)
++			if (ROM16(otable[table[4] + i*6]) == type)
+ 				break;
+ 		}
  
- static int
--nv40_mpeg_fini(struct drm_device *dev, int engine)
-+nv40_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
- {
- 	/*XXX: context save? */
- 	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
-diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
-index e25cbb4..d27dcf0 100644
---- a/drivers/gpu/drm/nouveau/nv50_graph.c
-+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
-@@ -125,7 +125,6 @@ static void
- nv50_graph_init_reset(struct drm_device *dev)
- {
- 	uint32_t pmc_e = NV_PMC_ENABLE_PGRAPH | (1 << 21);
--
- 	NV_DEBUG(dev, "\n");
+ 		if (i == otable[5]) {
+ 			NV_ERROR(dev, "Table 0x%04x not found for %d/%d, "
+ 				      "using first\n",
+-				 sub, dcbent->type, dcbent->or);
++				 type, dcbent->type, dcbent->or);
+ 			i = 0;
+ 		}
+ 	}
  
- 	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~pmc_e);
-@@ -255,9 +254,13 @@ nv50_graph_init(struct drm_device *dev, int engine)
- }
+-	if (pxclk == 0) {
++	if (pclk == 0) {
+ 		script = ROM16(otable[6]);
+ 		if (!script) {
+ 			NV_DEBUG_KMS(dev, "output script 0 not found\n");
+@@ -4581,9 +4570,9 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
+ 		}
  
- static int
--nv50_graph_fini(struct drm_device *dev, int engine)
-+nv50_graph_fini(struct drm_device *dev, int engine, bool suspend)
- {
--	NV_DEBUG(dev, "\n");
-+	nv_mask(dev, 0x400500, 0x00010001, 0x00000000);
-+	if (!nv_wait(dev, 0x400700, ~0, 0) && suspend) {
-+		nv_mask(dev, 0x400500, 0x00010001, 0x00010001);
-+		return -EBUSY;
-+	}
- 	nv50_graph_unload_context(dev);
- 	nv_wr32(dev, 0x40013c, 0x00000000);
+ 		NV_DEBUG_KMS(dev, "0x%04X: parsing output script 0\n", script);
+-		nouveau_bios_run_init_table(dev, script, dcbent);
++		nouveau_bios_run_init_table(dev, script, dcbent, crtc);
+ 	} else
+-	if (pxclk == -1) {
++	if (pclk == -1) {
+ 		script = ROM16(otable[8]);
+ 		if (!script) {
+ 			NV_DEBUG_KMS(dev, "output script 1 not found\n");
+@@ -4591,9 +4580,9 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
+ 		}
+ 
+ 		NV_DEBUG_KMS(dev, "0x%04X: parsing output script 1\n", script);
+-		nouveau_bios_run_init_table(dev, script, dcbent);
++		nouveau_bios_run_init_table(dev, script, dcbent, crtc);
+ 	} else
+-	if (pxclk == -2) {
++	if (pclk == -2) {
+ 		if (table[4] >= 12)
+ 			script = ROM16(otable[10]);
+ 		else
+@@ -4604,31 +4593,31 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
+ 		}
+ 
+ 		NV_DEBUG_KMS(dev, "0x%04X: parsing output script 2\n", script);
+-		nouveau_bios_run_init_table(dev, script, dcbent);
++		nouveau_bios_run_init_table(dev, script, dcbent, crtc);
+ 	} else
+-	if (pxclk > 0) {
++	if (pclk > 0) {
+ 		script = ROM16(otable[table[4] + i*6 + 2]);
+ 		if (script)
+-			script = clkcmptable(bios, script, pxclk);
++			script = clkcmptable(bios, script, pclk);
+ 		if (!script) {
+ 			NV_DEBUG_KMS(dev, "clock script 0 not found\n");
+ 			return 1;
+ 		}
+ 
+ 		NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 0\n", script);
+-		nouveau_bios_run_init_table(dev, script, dcbent);
++		nouveau_bios_run_init_table(dev, script, dcbent, crtc);
+ 	} else
+-	if (pxclk < 0) {
++	if (pclk < 0) {
+ 		script = ROM16(otable[table[4] + i*6 + 4]);
+ 		if (script)
+-			script = clkcmptable(bios, script, -pxclk);
++			script = clkcmptable(bios, script, -pclk);
+ 		if (!script) {
+ 			NV_DEBUG_KMS(dev, "clock script 1 not found\n");
+ 			return 1;
+ 		}
+ 
+ 		NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 1\n", script);
+-		nouveau_bios_run_init_table(dev, script, dcbent);
++		nouveau_bios_run_init_table(dev, script, dcbent, crtc);
+ 	}
+ 
+ 	return 0;
+@@ -5478,14 +5467,6 @@ parse_bit_U_tbl_entry(struct drm_device *dev, struct nvbios *bios,
  	return 0;
-diff --git a/drivers/gpu/drm/nouveau/nv50_mpeg.c b/drivers/gpu/drm/nouveau/nv50_mpeg.c
-index 1dc5913..b57a2d1 100644
---- a/drivers/gpu/drm/nouveau/nv50_mpeg.c
-+++ b/drivers/gpu/drm/nouveau/nv50_mpeg.c
-@@ -160,7 +160,7 @@ nv50_mpeg_init(struct drm_device *dev, int engine)
  }
  
- static int
--nv50_mpeg_fini(struct drm_device *dev, int engine)
-+nv50_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
- {
- 	/*XXX: context save for s/r */
- 	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
-diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c
-index 75b809a..edece9c 100644
---- a/drivers/gpu/drm/nouveau/nv84_crypt.c
-+++ b/drivers/gpu/drm/nouveau/nv84_crypt.c
-@@ -138,7 +138,7 @@ nv84_crypt_isr(struct drm_device *dev)
- }
+-static int
+-parse_bit_displayport_tbl_entry(struct drm_device *dev, struct nvbios *bios,
+-				struct bit_entry *bitentry)
+-{
+-	bios->display.dp_table_ptr = ROM16(bios->data[bitentry->offset]);
+-	return 0;
+-}
+-
+ struct bit_table {
+ 	const char id;
+ 	int (* const parse_fn)(struct drm_device *, struct nvbios *, struct bit_entry *);
+@@ -5559,7 +5540,6 @@ parse_bit_structure(struct nvbios *bios, const uint16_t bitoffset)
+ 	parse_bit_table(bios, bitoffset, &BIT_TABLE('L', lvds));
+ 	parse_bit_table(bios, bitoffset, &BIT_TABLE('T', tmds));
+ 	parse_bit_table(bios, bitoffset, &BIT_TABLE('U', U));
+-	parse_bit_table(bios, bitoffset, &BIT_TABLE('d', displayport));
  
- static int
--nv84_crypt_fini(struct drm_device *dev, int engine)
-+nv84_crypt_fini(struct drm_device *dev, int engine, bool suspend)
- {
- 	nv_wr32(dev, 0x102140, 0x00000000);
  	return 0;
-diff --git a/drivers/gpu/drm/nouveau/nva3_copy.c b/drivers/gpu/drm/nouveau/nva3_copy.c
-index b86820a..8f356d5 100644
---- a/drivers/gpu/drm/nouveau/nva3_copy.c
-+++ b/drivers/gpu/drm/nouveau/nva3_copy.c
-@@ -140,7 +140,7 @@ nva3_copy_init(struct drm_device *dev, int engine)
  }
+@@ -5884,9 +5864,15 @@ parse_dcb_gpio_table(struct nvbios *bios)
+ 			}
  
- static int
--nva3_copy_fini(struct drm_device *dev, int engine)
-+nva3_copy_fini(struct drm_device *dev, int engine, bool suspend)
+ 			e->line = (e->entry & 0x0000001f) >> 0;
+-			e->state_default = (e->entry & 0x01000000) >> 24;
+-			e->state[0] = (e->entry & 0x18000000) >> 27;
+-			e->state[1] = (e->entry & 0x60000000) >> 29;
++			if (gpio[0] == 0x40) {
++				e->state_default = (e->entry & 0x01000000) >> 24;
++				e->state[0] = (e->entry & 0x18000000) >> 27;
++				e->state[1] = (e->entry & 0x60000000) >> 29;
++			} else {
++				e->state_default = (e->entry & 0x00000080) >> 7;
++				e->state[0] = (entry[4] >> 4) & 3;
++				e->state[1] = (entry[4] >> 6) & 3;
++			}
+ 		}
+ 	}
+ 
+@@ -6156,7 +6142,14 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
+ 	}
+ 	case OUTPUT_DP:
+ 		entry->dpconf.sor.link = (conf & 0x00000030) >> 4;
+-		entry->dpconf.link_bw = (conf & 0x00e00000) >> 21;
++		switch ((conf & 0x00e00000) >> 21) {
++		case 0:
++			entry->dpconf.link_bw = 162000;
++			break;
++		default:
++			entry->dpconf.link_bw = 270000;
++			break;
++		}
+ 		switch ((conf & 0x0f000000) >> 24) {
+ 		case 0xf:
+ 			entry->dpconf.link_nr = 4;
+@@ -6769,7 +6762,7 @@ uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev)
+ 
+ void
+ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
+-			    struct dcb_entry *dcbent)
++			    struct dcb_entry *dcbent, int crtc)
  {
- 	nv_mask(dev, 0x104048, 0x00000003, 0x00000000);
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 	struct nvbios *bios = &dev_priv->vbios;
+@@ -6777,11 +6770,22 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
  
-diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.c b/drivers/gpu/drm/nouveau/nvc0_copy.c
-index 208fa7a..4d58c33 100644
---- a/drivers/gpu/drm/nouveau/nvc0_copy.c
-+++ b/drivers/gpu/drm/nouveau/nvc0_copy.c
-@@ -127,7 +127,7 @@ nvc0_copy_init(struct drm_device *dev, int engine)
+ 	spin_lock_bh(&bios->lock);
+ 	bios->display.output = dcbent;
++	bios->display.crtc = crtc;
+ 	parse_init_table(bios, table, &iexec);
+ 	bios->display.output = NULL;
+ 	spin_unlock_bh(&bios->lock);
  }
  
- static int
--nvc0_copy_fini(struct drm_device *dev, int engine)
-+nvc0_copy_fini(struct drm_device *dev, int engine, bool suspend)
++void
++nouveau_bios_init_exec(struct drm_device *dev, uint16_t table)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nvbios *bios = &dev_priv->vbios;
++	struct init_exec iexec = { true, false };
++
++	parse_init_table(bios, table, &iexec);
++}
++
+ static bool NVInitVBIOS(struct drm_device *dev)
  {
- 	struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+@@ -6863,9 +6867,8 @@ nouveau_run_vbios_init(struct drm_device *dev)
  
-diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
-index ca6db20..69c6522 100644
---- a/drivers/gpu/drm/nouveau/nvc0_graph.c
-+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
-@@ -248,7 +248,7 @@ nvc0_graph_object_new(struct nouveau_channel *chan, int engine,
- }
+ 	if (dev_priv->card_type >= NV_50) {
+ 		for (i = 0; i < bios->dcb.entries; i++) {
+-			nouveau_bios_run_display_table(dev,
+-						       &bios->dcb.entry[i],
+-						       0, 0);
++			nouveau_bios_run_display_table(dev, 0, 0,
++						       &bios->dcb.entry[i], -1);
+ 		}
+ 	}
  
- static int
--nvc0_graph_fini(struct drm_device *dev, int engine)
-+nvc0_graph_fini(struct drm_device *dev, int engine, bool suspend)
+diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
+index 050c314..8adb69e 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
++++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
+@@ -289,8 +289,8 @@ struct nvbios {
+ 
+ 	struct {
+ 		struct dcb_entry *output;
++		int crtc;
+ 		uint16_t script_table_ptr;
+-		uint16_t dp_table_ptr;
+ 	} display;
+ 
+ 	struct {
+diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
+index 890d50e..7226f41 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
++++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
+@@ -956,7 +956,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+ 			break;
+ 		}
+ 
+-		if (dev_priv->card_type == NV_C0)
++		if (dev_priv->card_type >= NV_C0)
+ 			page_shift = node->page_shift;
+ 		else
+ 			page_shift = 12;
+diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
+index b0d753f..a319d56 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
++++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
+@@ -411,13 +411,17 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
+ 		return ret;
+ 	init->channel  = chan->id;
+ 
+-	if (chan->dma.ib_max)
+-		init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
+-					NOUVEAU_GEM_DOMAIN_GART;
+-	else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM)
++	if (nouveau_vram_pushbuf == 0) {
++		if (chan->dma.ib_max)
++			init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
++						NOUVEAU_GEM_DOMAIN_GART;
++		else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM)
++			init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
++		else
++			init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
++	} else {
+ 		init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
+-	else
+-		init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
++	}
+ 
+ 	if (dev_priv->card_type < NV_C0) {
+ 		init->subchan[0].handle = NvM2MF;
+diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
+index 939d4df..e0d275e 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
++++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
+@@ -39,7 +39,7 @@
+ 
+ static void nouveau_connector_hotplug(void *, int);
+ 
+-static struct nouveau_encoder *
++struct nouveau_encoder *
+ find_encoder(struct drm_connector *connector, int type)
  {
- 	return 0;
- }
+ 	struct drm_device *dev = connector->dev;
+@@ -116,10 +116,6 @@ nouveau_connector_destroy(struct drm_connector *connector)
+ 				      nouveau_connector_hotplug, connector);
+ 	}
+ 
+-	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
+-	    connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+-		nouveau_backlight_exit(connector);
+-
+ 	kfree(nv_connector->edid);
+ 	drm_sysfs_connector_remove(connector);
+ 	drm_connector_cleanup(connector);
+@@ -712,11 +708,8 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
+ 	case OUTPUT_TV:
+ 		return get_slave_funcs(encoder)->mode_valid(encoder, mode);
+ 	case OUTPUT_DP:
+-		if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7)
+-			max_clock = nv_encoder->dp.link_nr * 270000;
+-		else
+-			max_clock = nv_encoder->dp.link_nr * 162000;
+-
++		max_clock  = nv_encoder->dp.link_nr;
++		max_clock *= nv_encoder->dp.link_bw;
+ 		clock = clock * nouveau_connector_bpp(connector) / 8;
+ 		break;
+ 	default:
+@@ -871,7 +864,6 @@ nouveau_connector_create(struct drm_device *dev, int index)
+ 					dev->mode_config.scaling_mode_property,
+ 					nv_connector->scaling_mode);
+ 		}
+-		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ 		/* fall-through */
+ 	case DCB_CONNECTOR_TV_0:
+ 	case DCB_CONNECTOR_TV_1:
+@@ -888,27 +880,20 @@ nouveau_connector_create(struct drm_device *dev, int index)
+ 				dev->mode_config.dithering_mode_property,
+ 				nv_connector->use_dithering ?
+ 				DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
+-
+-		if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) {
+-			if (dev_priv->card_type >= NV_50)
+-				connector->polled = DRM_CONNECTOR_POLL_HPD;
+-			else
+-				connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+-		}
+ 		break;
+ 	}
+ 
+-	if (pgpio->irq_register) {
++	if (nv_connector->dcb->gpio_tag != 0xff && pgpio->irq_register) {
+ 		pgpio->irq_register(dev, nv_connector->dcb->gpio_tag,
+ 				    nouveau_connector_hotplug, connector);
++
++		connector->polled = DRM_CONNECTOR_POLL_HPD;
++	} else {
++		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ 	}
+ 
+ 	drm_sysfs_connector_add(connector);
+ 
+-	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
+-	    connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+-		nouveau_backlight_init(connector);
+-
+ 	dcb->drm = connector;
+ 	return dcb->drm;
+ 
+@@ -925,22 +910,13 @@ nouveau_connector_hotplug(void *data, int plugged)
+ 	struct drm_connector *connector = data;
+ 	struct drm_device *dev = connector->dev;
+ 
+-	NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un",
+-		drm_get_connector_name(connector));
+-
+-	if (connector->encoder && connector->encoder->crtc &&
+-	    connector->encoder->crtc->enabled) {
+-		struct nouveau_encoder *nv_encoder = nouveau_encoder(connector->encoder);
+-		struct drm_encoder_helper_funcs *helper =
+-			connector->encoder->helper_private;
++	NV_DEBUG(dev, "%splugged %s\n", plugged ? "" : "un",
++		 drm_get_connector_name(connector));
+ 
+-		if (nv_encoder->dcb->type == OUTPUT_DP) {
+-			if (plugged)
+-				helper->dpms(connector->encoder, DRM_MODE_DPMS_ON);
+-			else
+-				helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF);
+-		}
+-	}
++	if (plugged)
++		drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
++	else
++		drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+ 
+ 	drm_helper_hpd_irq_event(dev);
+ }
+diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h
+index cb1ce2a..bf8e128 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_crtc.h
++++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h
+@@ -82,14 +82,13 @@ static inline struct drm_crtc *to_drm_crtc(struct nouveau_crtc *crtc)
+ }
+ 
+ int nv50_crtc_create(struct drm_device *dev, int index);
+-int nv50_cursor_init(struct nouveau_crtc *);
+-void nv50_cursor_fini(struct nouveau_crtc *);
+ int nv50_crtc_cursor_set(struct drm_crtc *drm_crtc, struct drm_file *file_priv,
+ 			 uint32_t buffer_handle, uint32_t width,
+ 			 uint32_t height);
+ int nv50_crtc_cursor_move(struct drm_crtc *drm_crtc, int x, int y);
+ 
+ int nv04_cursor_init(struct nouveau_crtc *);
++int nv50_cursor_init(struct nouveau_crtc *);
+ 
+ struct nouveau_connector *
+ nouveau_crtc_connector_get(struct nouveau_crtc *crtc);
+diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
+index eb514ea..ddbabef 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_display.c
++++ b/drivers/gpu/drm/nouveau/nouveau_display.c
+@@ -105,9 +105,12 @@ nouveau_framebuffer_init(struct drm_device *dev,
+ 		if (dev_priv->chipset == 0x50)
+ 			nv_fb->r_format |= (tile_flags << 8);
+ 
+-		if (!tile_flags)
+-			nv_fb->r_pitch = 0x00100000 | fb->pitch;
+-		else {
++		if (!tile_flags) {
++			if (dev_priv->card_type < NV_D0)
++				nv_fb->r_pitch = 0x00100000 | fb->pitch;
++			else
++				nv_fb->r_pitch = 0x01000000 | fb->pitch;
++		} else {
+ 			u32 mode = nvbo->tile_mode;
+ 			if (dev_priv->card_type >= NV_C0)
+ 				mode >>= 4;
+diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
+index 7beb82a..de5efe7 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
++++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
+@@ -28,418 +28,619 @@
+ #include "nouveau_i2c.h"
+ #include "nouveau_connector.h"
+ #include "nouveau_encoder.h"
++#include "nouveau_crtc.h"
++
++/******************************************************************************
++ * aux channel util functions
++ *****************************************************************************/
++#define AUX_DBG(fmt, args...) do {                                             \
++	if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_AUXCH) {                     \
++		NV_PRINTK(KERN_DEBUG, dev, "AUXCH(%d): " fmt, ch, ##args);     \
++	}                                                                      \
++} while (0)
++#define AUX_ERR(fmt, args...) NV_ERROR(dev, "AUXCH(%d): " fmt, ch, ##args)
++
++static void
++auxch_fini(struct drm_device *dev, int ch)
++{
++	nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
++}
+ 
+ static int
+-auxch_rd(struct drm_encoder *encoder, int address, uint8_t *buf, int size)
++auxch_init(struct drm_device *dev, int ch)
+ {
+-	struct drm_device *dev = encoder->dev;
+-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+-	struct nouveau_i2c_chan *auxch;
+-	int ret;
+-
+-	auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
+-	if (!auxch)
+-		return -ENODEV;
+-
+-	ret = nouveau_dp_auxch(auxch, 9, address, buf, size);
+-	if (ret)
+-		return ret;
++	const u32 unksel = 1; /* nfi which to use, or if it matters.. */
++	const u32 ureq = unksel ? 0x00100000 : 0x00200000;
++	const u32 urep = unksel ? 0x01000000 : 0x02000000;
++	u32 ctrl, timeout;
++
++	/* wait up to 1ms for any previous transaction to be done... */
++	timeout = 1000;
++	do {
++		ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
++		udelay(1);
++		if (!timeout--) {
++			AUX_ERR("begin idle timeout 0x%08x", ctrl);
++			return -EBUSY;
++		}
++	} while (ctrl & 0x03010000);
++
++	/* set some magic, and wait up to 1ms for it to appear */
++	nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
++	timeout = 1000;
++	do {
++		ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
++		udelay(1);
++		if (!timeout--) {
++			AUX_ERR("magic wait 0x%08x\n", ctrl);
++			auxch_fini(dev, ch);
++			return -EBUSY;
++		}
++	} while ((ctrl & 0x03000000) != urep);
+ 
+ 	return 0;
+ }
+ 
+ static int
+-auxch_wr(struct drm_encoder *encoder, int address, uint8_t *buf, int size)
++auxch_tx(struct drm_device *dev, int ch, u8 type, u32 addr, u8 *data, u8 size)
+ {
+-	struct drm_device *dev = encoder->dev;
+-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+-	struct nouveau_i2c_chan *auxch;
+-	int ret;
++	u32 ctrl, stat, timeout, retries;
++	u32 xbuf[4] = {};
++	int ret, i;
+ 
+-	auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
+-	if (!auxch)
+-		return -ENODEV;
++	AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
+ 
+-	ret = nouveau_dp_auxch(auxch, 8, address, buf, size);
+-	return ret;
+-}
++	ret = auxch_init(dev, ch);
++	if (ret)
++		goto out;
+ 
+-static int
+-nouveau_dp_lane_count_set(struct drm_encoder *encoder, uint8_t cmd)
+-{
+-	struct drm_device *dev = encoder->dev;
+-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+-	uint32_t tmp;
+-	int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1);
+-
+-	tmp  = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
+-	tmp &= ~(NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED |
+-		 NV50_SOR_DP_CTRL_LANE_MASK);
+-	tmp |= ((1 << (cmd & DP_LANE_COUNT_MASK)) - 1) << 16;
+-	if (cmd & DP_LANE_COUNT_ENHANCED_FRAME_EN)
+-		tmp |= NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED;
+-	nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
+-
+-	return auxch_wr(encoder, DP_LANE_COUNT_SET, &cmd, 1);
+-}
++	stat = nv_rd32(dev, 0x00e4e8 + (ch * 0x50));
++	if (!(stat & 0x10000000)) {
++		AUX_DBG("sink not detected\n");
++		ret = -ENXIO;
++		goto out;
++	}
+ 
+-static int
+-nouveau_dp_link_bw_set(struct drm_encoder *encoder, uint8_t cmd)
+-{
+-	struct drm_device *dev = encoder->dev;
+-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+-	uint32_t tmp;
+-	int reg = 0x614300 + (nv_encoder->or * 0x800);
++	if (!(type & 1)) {
++		memcpy(xbuf, data, size);
++		for (i = 0; i < 16; i += 4) {
++			AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
++			nv_wr32(dev, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]);
++		}
++	}
+ 
+-	tmp  = nv_rd32(dev, reg);
+-	tmp &= 0xfff3ffff;
+-	if (cmd == DP_LINK_BW_2_7)
+-		tmp |= 0x00040000;
+-	nv_wr32(dev, reg, tmp);
++	ctrl  = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
++	ctrl &= ~0x0001f0ff;
++	ctrl |= type << 12;
++	ctrl |= size - 1;
++	nv_wr32(dev, 0x00e4e0 + (ch * 0x50), addr);
++
++	/* retry transaction a number of times on failure... */
++	ret = -EREMOTEIO;
++	for (retries = 0; retries < 32; retries++) {
++		/* reset, and delay a while if this is a retry */
++		nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
++		nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
++		if (retries)
++			udelay(400);
++
++		/* transaction request, wait up to 1ms for it to complete */
++		nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
++
++		timeout = 1000;
++		do {
++			ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
++			udelay(1);
++			if (!timeout--) {
++				AUX_ERR("tx req timeout 0x%08x\n", ctrl);
++				goto out;
++			}
++		} while (ctrl & 0x00010000);
+ 
+-	return auxch_wr(encoder, DP_LINK_BW_SET, &cmd, 1);
+-}
++		/* read status, and check if transaction completed ok */
++		stat = nv_mask(dev, 0x00e4e8 + (ch * 0x50), 0, 0);
++		if (!(stat & 0x000f0f00)) {
++			ret = 0;
++			break;
++		}
+ 
+-static int
+-nouveau_dp_link_train_set(struct drm_encoder *encoder, int pattern)
+-{
+-	struct drm_device *dev = encoder->dev;
+-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+-	uint32_t tmp;
+-	uint8_t cmd;
+-	int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1);
+-	int ret;
++		AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
++	}
+ 
+-	tmp  = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
+-	tmp &= ~NV50_SOR_DP_CTRL_TRAINING_PATTERN;
+-	tmp |= (pattern << 24);
+-	nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
++	if (type & 1) {
++		for (i = 0; i < 16; i += 4) {
++			xbuf[i / 4] = nv_rd32(dev, 0x00e4d0 + (ch * 0x50) + i);
++			AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
++		}
++		memcpy(data, xbuf, size);
++	}
+ 
+-	ret = auxch_rd(encoder, DP_TRAINING_PATTERN_SET, &cmd, 1);
+-	if (ret)
+-		return ret;
+-	cmd &= ~DP_TRAINING_PATTERN_MASK;
+-	cmd |= (pattern & DP_TRAINING_PATTERN_MASK);
+-	return auxch_wr(encoder, DP_TRAINING_PATTERN_SET, &cmd, 1);
++out:
++	auxch_fini(dev, ch);
++	return ret;
+ }
+ 
+-static int
+-nouveau_dp_max_voltage_swing(struct drm_encoder *encoder)
++static u32
++dp_link_bw_get(struct drm_device *dev, int or, int link)
+ {
+-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+-	struct drm_device *dev = encoder->dev;
+-	struct bit_displayport_encoder_table_entry *dpse;
+-	struct bit_displayport_encoder_table *dpe;
+-	int i, dpe_headerlen, max_vs = 0;
+-
+-	dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
+-	if (!dpe)
+-		return false;
+-	dpse = (void *)((char *)dpe + dpe_headerlen);
++	u32 ctrl = nv_rd32(dev, 0x614300 + (or * 0x800));
++	if (!(ctrl & 0x000c0000))
++		return 162000;
++	return 270000;
++}
+ 
+-	for (i = 0; i < dpe_headerlen; i++, dpse++) {
+-		if (dpse->vs_level > max_vs)
+-			max_vs = dpse->vs_level;
++static int
++dp_lane_count_get(struct drm_device *dev, int or, int link)
++{
++	u32 ctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
++	switch (ctrl & 0x000f0000) {
++	case 0x00010000: return 1;
++	case 0x00030000: return 2;
++	default:
++		return 4;
+ 	}
+-
+-	return max_vs;
+ }
+ 
+-static int
+-nouveau_dp_max_pre_emphasis(struct drm_encoder *encoder, int vs)
++void
++nouveau_dp_tu_update(struct drm_device *dev, int or, int link, u32 clk, u32 bpp)
+ {
+-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+-	struct drm_device *dev = encoder->dev;
+-	struct bit_displayport_encoder_table_entry *dpse;
+-	struct bit_displayport_encoder_table *dpe;
+-	int i, dpe_headerlen, max_pre = 0;
++	const u32 symbol = 100000;
++	int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
++	int TU, VTUi, VTUf, VTUa;
++	u64 link_data_rate, link_ratio, unk;
++	u32 best_diff = 64 * symbol;
++	u32 link_nr, link_bw, r;
++
++	/* calculate packed data rate for each lane */
++	link_nr = dp_lane_count_get(dev, or, link);
++	link_data_rate = (clk * bpp / 8) / link_nr;
++
++	/* calculate ratio of packed data rate to link symbol rate */
++	link_bw = dp_link_bw_get(dev, or, link);
++	link_ratio = link_data_rate * symbol;
++	r = do_div(link_ratio, link_bw);
++
++	for (TU = 64; TU >= 32; TU--) {
++		/* calculate average number of valid symbols in each TU */
++		u32 tu_valid = link_ratio * TU;
++		u32 calc, diff;
++
++		/* find a hw representation for the fraction.. */
++		VTUi = tu_valid / symbol;
++		calc = VTUi * symbol;
++		diff = tu_valid - calc;
++		if (diff) {
++			if (diff >= (symbol / 2)) {
++				VTUf = symbol / (symbol - diff);
++				if (symbol - (VTUf * diff))
++					VTUf++;
++
++				if (VTUf <= 15) {
++					VTUa  = 1;
++					calc += symbol - (symbol / VTUf);
++				} else {
++					VTUa  = 0;
++					VTUf  = 1;
++					calc += symbol;
++				}
++			} else {
++				VTUa  = 0;
++				VTUf  = min((int)(symbol / diff), 15);
++				calc += symbol / VTUf;
++			}
+ 
+-	dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
+-	if (!dpe)
+-		return false;
+-	dpse = (void *)((char *)dpe + dpe_headerlen);
++			diff = calc - tu_valid;
++		} else {
++			/* no remainder, but the hw doesn't like the fractional
++			 * part to be zero.  decrement the integer part and
++			 * have the fraction add a whole symbol back
++			 */
++			VTUa = 0;
++			VTUf = 1;
++			VTUi--;
++		}
+ 
+-	for (i = 0; i < dpe_headerlen; i++, dpse++) {
+-		if (dpse->vs_level != vs)
+-			continue;
++		if (diff < best_diff) {
++			best_diff = diff;
++			bestTU = TU;
++			bestVTUa = VTUa;
++			bestVTUf = VTUf;
++			bestVTUi = VTUi;
++			if (diff == 0)
++				break;
++		}
++	}
+ 
+-		if (dpse->pre_level > max_pre)
+-			max_pre = dpse->pre_level;
++	if (!bestTU) {
++		NV_ERROR(dev, "DP: unable to find suitable config\n");
++		return;
+ 	}
+ 
+-	return max_pre;
++	/* XXX close to vbios numbers, but not right */
++	unk  = (symbol - link_ratio) * bestTU;
++	unk *= link_ratio;
++	r = do_div(unk, symbol);
++	r = do_div(unk, symbol);
++	unk += 6;
++
++	nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2);
++	nv_mask(dev, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 |
++							     bestVTUf << 16 |
++							     bestVTUi << 8 |
++							     unk);
+ }
+ 
+-static bool
+-nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config)
++u8 *
++nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
+ {
+-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+-	struct drm_device *dev = encoder->dev;
+-	struct bit_displayport_encoder_table *dpe;
+-	int ret, i, dpe_headerlen, vs = 0, pre = 0;
+-	uint8_t request[2];
+-
+-	dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
+-	if (!dpe)
+-		return false;
+-
+-	ret = auxch_rd(encoder, DP_ADJUST_REQUEST_LANE0_1, request, 2);
+-	if (ret)
+-		return false;
+-
+-	NV_DEBUG_KMS(dev, "\t\tadjust 0x%02x 0x%02x\n", request[0], request[1]);
+-
+-	/* Keep all lanes at the same level.. */
+-	for (i = 0; i < nv_encoder->dp.link_nr; i++) {
+-		int lane_req = (request[i >> 1] >> ((i & 1) << 2)) & 0xf;
+-		int lane_vs = lane_req & 3;
+-		int lane_pre = (lane_req >> 2) & 3;
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nvbios *bios = &dev_priv->vbios;
++	struct bit_entry d;
++	u8 *table;
++	int i;
++
++	if (bit_table(dev, 'd', &d)) {
++		NV_ERROR(dev, "BIT 'd' table not found\n");
++		return NULL;
++	}
+ 
+-		if (lane_vs > vs)
+-			vs = lane_vs;
+-		if (lane_pre > pre)
+-			pre = lane_pre;
++	if (d.version != 1) {
++		NV_ERROR(dev, "BIT 'd' table version %d unknown\n", d.version);
++		return NULL;
+ 	}
+ 
+-	if (vs >= nouveau_dp_max_voltage_swing(encoder)) {
+-		vs  = nouveau_dp_max_voltage_swing(encoder);
+-		vs |= 4;
++	table = ROMPTR(bios, d.data[0]);
++	if (!table) {
++		NV_ERROR(dev, "displayport table pointer invalid\n");
++		return NULL;
+ 	}
+ 
+-	if (pre >= nouveau_dp_max_pre_emphasis(encoder, vs & 3)) {
+-		pre  = nouveau_dp_max_pre_emphasis(encoder, vs & 3);
+-		pre |= 4;
++	switch (table[0]) {
++	case 0x20:
++	case 0x21:
++	case 0x30:
++		break;
++	default:
++		NV_ERROR(dev, "displayport table 0x%02x unknown\n", table[0]);
++		return NULL;
+ 	}
+ 
+-	/* Update the configuration for all lanes.. */
+-	for (i = 0; i < nv_encoder->dp.link_nr; i++)
+-		config[i] = (pre << 3) | vs;
++	for (i = 0; i < table[3]; i++) {
++		*entry = ROMPTR(bios, table[table[1] + (i * table[2])]);
++		if (*entry && bios_encoder_match(dcb, ROM32((*entry)[0])))
++			return table;
++	}
+ 
+-	return true;
++	NV_ERROR(dev, "displayport encoder table not found\n");
++	return NULL;
+ }
+ 
+-static bool
+-nouveau_dp_link_train_commit(struct drm_encoder *encoder, uint8_t *config)
+-{
+-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+-	struct drm_device *dev = encoder->dev;
+-	struct bit_displayport_encoder_table_entry *dpse;
+-	struct bit_displayport_encoder_table *dpe;
+-	int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1);
+-	int dpe_headerlen, ret, i;
++/******************************************************************************
++ * link training
++ *****************************************************************************/
++struct dp_state {
++	struct dcb_entry *dcb;
++	u8 *table;
++	u8 *entry;
++	int auxch;
++	int crtc;
++	int or;
++	int link;
++	u8 *dpcd;
++	int link_nr;
++	u32 link_bw;
++	u8  stat[6];
++	u8  conf[4];
++};
+ 
+-	NV_DEBUG_KMS(dev, "\t\tconfig 0x%02x 0x%02x 0x%02x 0x%02x\n",
+-		 config[0], config[1], config[2], config[3]);
++static void
++dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	int or = dp->or, link = dp->link;
++	u8 *entry, sink[2];
++	u32 dp_ctrl;
++	u16 script;
++
++	NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
++
++	/* set selected link rate on source */
++	switch (dp->link_bw) {
++	case 270000:
++		nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00040000);
++		sink[0] = DP_LINK_BW_2_7;
++		break;
++	default:
++		nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00000000);
++		sink[0] = DP_LINK_BW_1_62;
++		break;
++	}
+ 
+-	dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
+-	if (!dpe)
+-		return false;
+-	dpse = (void *)((char *)dpe + dpe_headerlen);
++	/* offset +0x0a of each dp encoder table entry is a pointer to another
++	 * table, that has (among other things) pointers to more scripts that
++	 * need to be executed, this time depending on link speed.
++	 */
++	entry = ROMPTR(&dev_priv->vbios, dp->entry[10]);
++	if (entry) {
++		if (dp->table[0] < 0x30) {
++			while (dp->link_bw < (ROM16(entry[0]) * 10))
++				entry += 4;
++			script = ROM16(entry[2]);
++		} else {
++			while (dp->link_bw < (entry[0] * 27000))
++				entry += 3;
++			script = ROM16(entry[1]);
++		}
+ 
+-	for (i = 0; i < dpe->record_nr; i++, dpse++) {
+-		if (dpse->vs_level == (config[0] & 3) &&
+-		    dpse->pre_level == ((config[0] >> 3) & 3))
+-			break;
++		nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
+ 	}
+-	BUG_ON(i == dpe->record_nr);
+-
+-	for (i = 0; i < nv_encoder->dp.link_nr; i++) {
+-		const int shift[4] = { 16, 8, 0, 24 };
+-		uint32_t mask = 0xff << shift[i];
+-		uint32_t reg0, reg1, reg2;
+-
+-		reg0  = nv_rd32(dev, NV50_SOR_DP_UNK118(or, link)) & ~mask;
+-		reg0 |= (dpse->reg0 << shift[i]);
+-		reg1  = nv_rd32(dev, NV50_SOR_DP_UNK120(or, link)) & ~mask;
+-		reg1 |= (dpse->reg1 << shift[i]);
+-		reg2  = nv_rd32(dev, NV50_SOR_DP_UNK130(or, link)) & 0xffff00ff;
+-		reg2 |= (dpse->reg2 << 8);
+-		nv_wr32(dev, NV50_SOR_DP_UNK118(or, link), reg0);
+-		nv_wr32(dev, NV50_SOR_DP_UNK120(or, link), reg1);
+-		nv_wr32(dev, NV50_SOR_DP_UNK130(or, link), reg2);
++
++	/* configure lane count on the source */
++	dp_ctrl = ((1 << dp->link_nr) - 1) << 16;
++	sink[1] = dp->link_nr;
++	if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP) {
++		dp_ctrl |= 0x00004000;
++		sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+ 	}
+ 
+-	ret = auxch_wr(encoder, DP_TRAINING_LANE0_SET, config, 4);
+-	if (ret)
+-		return false;
++	nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x001f4000, dp_ctrl);
+ 
+-	return true;
++	/* inform the sink of the new configuration */
++	auxch_tx(dev, dp->auxch, 8, DP_LINK_BW_SET, sink, 2);
+ }
+ 
+-bool
+-nouveau_dp_link_train(struct drm_encoder *encoder)
++static void
++dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 tp)
+ {
+-	struct drm_device *dev = encoder->dev;
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
+-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+-	struct nouveau_connector *nv_connector;
+-	struct bit_displayport_encoder_table *dpe;
+-	int dpe_headerlen;
+-	uint8_t config[4], status[3];
+-	bool cr_done, cr_max_vs, eq_done, hpd_state;
+-	int ret = 0, i, tries, voltage;
++	u8 sink_tp;
+ 
+-	NV_DEBUG_KMS(dev, "link training!!\n");
++	NV_DEBUG_KMS(dev, "training pattern %d\n", tp);
+ 
+-	nv_connector = nouveau_encoder_connector_get(nv_encoder);
+-	if (!nv_connector)
+-		return false;
++	nv_mask(dev, NV50_SOR_DP_CTRL(dp->or, dp->link), 0x0f000000, tp << 24);
+ 
+-	dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
+-	if (!dpe) {
+-		NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or);
+-		return false;
+-	}
++	auxch_tx(dev, dp->auxch, 9, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
++	sink_tp &= ~DP_TRAINING_PATTERN_MASK;
++	sink_tp |= tp;
++	auxch_tx(dev, dp->auxch, 8, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
++}
+ 
+-	/* disable hotplug detect, this flips around on some panels during
+-	 * link training.
+-	 */
+-	hpd_state = pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false);
++static const u8 nv50_lane_map[] = { 16, 8, 0, 24 };
++static const u8 nvaf_lane_map[] = { 24, 16, 8, 0 };
++
++static int
++dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	u32 mask = 0, drv = 0, pre = 0, unk = 0;
++	const u8 *shifts;
++	int link = dp->link;
++	int or = dp->or;
++	int i;
++
++	if (dev_priv->chipset != 0xaf)
++		shifts = nv50_lane_map;
++	else
++		shifts = nvaf_lane_map;
++
++	for (i = 0; i < dp->link_nr; i++) {
++		u8 *conf = dp->entry + dp->table[4];
++		u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
++		u8 lpre = (lane & 0x0c) >> 2;
++		u8 lvsw = (lane & 0x03) >> 0;
++
++		mask |= 0xff << shifts[i];
++		unk |= 1 << (shifts[i] >> 3);
++
++		dp->conf[i] = (lpre << 3) | lvsw;
++		if (lvsw == DP_TRAIN_VOLTAGE_SWING_1200)
++			dp->conf[i] |= DP_TRAIN_MAX_SWING_REACHED;
++		if (lpre == DP_TRAIN_PRE_EMPHASIS_9_5)
++			dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
++
++		NV_DEBUG_KMS(dev, "config lane %d %02x\n", i, dp->conf[i]);
++
++		if (dp->table[0] < 0x30) {
++			u8 *last = conf + (dp->entry[4] * dp->table[5]);
++			while (lvsw != conf[0] || lpre != conf[1]) {
++				conf += dp->table[5];
++				if (conf >= last)
++					return -EINVAL;
++			}
++
++			conf += 2;
++		} else {
++			/* no lookup table anymore, set entries for each
++			 * combination of voltage swing and pre-emphasis
++			 * level allowed by the DP spec.
++			 */
++			switch (lvsw) {
++			case 0: lpre += 0; break;
++			case 1: lpre += 4; break;
++			case 2: lpre += 7; break;
++			case 3: lpre += 9; break;
++			}
++
++			conf = conf + (lpre * dp->table[5]);
++			conf++;
++		}
+ 
+-	if (dpe->script0) {
+-		NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
+-		nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0),
+-					    nv_encoder->dcb);
++		drv |= conf[0] << shifts[i];
++		pre |= conf[1] << shifts[i];
++		unk  = (unk & ~0x0000ff00) | (conf[2] << 8);
+ 	}
+ 
+-train:
+-	cr_done = eq_done = false;
++	nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, drv);
++	nv_mask(dev, NV50_SOR_DP_UNK120(or, link), mask, pre);
++	nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000ff0f, unk);
+ 
+-	/* set link configuration */
+-	NV_DEBUG_KMS(dev, "\tbegin train: bw %d, lanes %d\n",
+-		 nv_encoder->dp.link_bw, nv_encoder->dp.link_nr);
++	return auxch_tx(dev, dp->auxch, 8, DP_TRAINING_LANE0_SET, dp->conf, 4);
++}
+ 
+-	ret = nouveau_dp_link_bw_set(encoder, nv_encoder->dp.link_bw);
+-	if (ret)
+-		return false;
++static int
++dp_link_train_update(struct drm_device *dev, struct dp_state *dp, u32 delay)
++{
++	int ret;
+ 
+-	config[0] = nv_encoder->dp.link_nr;
+-	if (nv_encoder->dp.dpcd_version >= 0x11 &&
+-	    nv_encoder->dp.enhanced_frame)
+-		config[0] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
++	udelay(delay);
+ 
+-	ret = nouveau_dp_lane_count_set(encoder, config[0]);
++	ret = auxch_tx(dev, dp->auxch, 9, DP_LANE0_1_STATUS, dp->stat, 6);
+ 	if (ret)
+-		return false;
++		return ret;
+ 
+-	/* clock recovery */
+-	NV_DEBUG_KMS(dev, "\tbegin cr\n");
+-	ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_1);
+-	if (ret)
+-		goto stop;
++	NV_DEBUG_KMS(dev, "status %02x %02x %02x %02x %02x %02x\n",
++		     dp->stat[0], dp->stat[1], dp->stat[2], dp->stat[3],
++		     dp->stat[4], dp->stat[5]);
++	return 0;
++}
+ 
+-	tries = 0;
+-	voltage = -1;
+-	memset(config, 0x00, sizeof(config));
+-	for (;;) {
+-		if (!nouveau_dp_link_train_commit(encoder, config))
+-			break;
++static int
++dp_link_train_cr(struct drm_device *dev, struct dp_state *dp)
++{
++	bool cr_done = false, abort = false;
++	int voltage = dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
++	int tries = 0, i;
+ 
+-		udelay(100);
++	dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_1);
+ 
+-		ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 2);
+-		if (ret)
++	do {
++		if (dp_link_train_commit(dev, dp) ||
++		    dp_link_train_update(dev, dp, 100))
+ 			break;
+-		NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n",
+-			 status[0], status[1]);
+ 
+ 		cr_done = true;
+-		cr_max_vs = false;
+-		for (i = 0; i < nv_encoder->dp.link_nr; i++) {
+-			int lane = (status[i >> 1] >> ((i & 1) * 4)) & 0xf;
+-
++		for (i = 0; i < dp->link_nr; i++) {
++			u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
+ 			if (!(lane & DP_LANE_CR_DONE)) {
+ 				cr_done = false;
+-				if (config[i] & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED)
+-					cr_max_vs = true;
++				if (dp->conf[i] & DP_TRAIN_MAX_SWING_REACHED)
++					abort = true;
+ 				break;
+ 			}
+ 		}
+ 
+-		if ((config[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) {
+-			voltage = config[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
++		if ((dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) {
++			voltage = dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+ 			tries = 0;
+ 		}
++	} while (!cr_done && !abort && ++tries < 5);
+ 
+-		if (cr_done || cr_max_vs || (++tries == 5))
+-			break;
+-
+-		if (!nouveau_dp_link_train_adjust(encoder, config))
+-			break;
+-	}
+-
+-	if (!cr_done)
+-		goto stop;
++	return cr_done ? 0 : -1;
++}
+ 
+-	/* channel equalisation */
+-	NV_DEBUG_KMS(dev, "\tbegin eq\n");
+-	ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_2);
+-	if (ret)
+-		goto stop;
++static int
++dp_link_train_eq(struct drm_device *dev, struct dp_state *dp)
++{
++	bool eq_done, cr_done = true;
++	int tries = 0, i;
+ 
+-	for (tries = 0; tries <= 5; tries++) {
+-		udelay(400);
++	dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_2);
+ 
+-		ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 3);
+-		if (ret)
++	do {
++		if (dp_link_train_update(dev, dp, 400))
+ 			break;
+-		NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n",
+-			 status[0], status[1]);
+ 
+-		eq_done = true;
+-		if (!(status[2] & DP_INTERLANE_ALIGN_DONE))
+-			eq_done = false;
+-
+-		for (i = 0; eq_done && i < nv_encoder->dp.link_nr; i++) {
+-			int lane = (status[i >> 1] >> ((i & 1) * 4)) & 0xf;
+-
+-			if (!(lane & DP_LANE_CR_DONE)) {
++		eq_done = !!(dp->stat[2] & DP_INTERLANE_ALIGN_DONE);
++		for (i = 0; i < dp->link_nr && eq_done; i++) {
++			u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
++			if (!(lane & DP_LANE_CR_DONE))
+ 				cr_done = false;
+-				break;
+-			}
+-
+ 			if (!(lane & DP_LANE_CHANNEL_EQ_DONE) ||
+-			    !(lane & DP_LANE_SYMBOL_LOCKED)) {
++			    !(lane & DP_LANE_SYMBOL_LOCKED))
+ 				eq_done = false;
+-				break;
+-			}
+ 		}
+ 
+-		if (eq_done || !cr_done)
++		if (dp_link_train_commit(dev, dp))
+ 			break;
++	} while (!eq_done && cr_done && ++tries <= 5);
+ 
+-		if (!nouveau_dp_link_train_adjust(encoder, config) ||
+-		    !nouveau_dp_link_train_commit(encoder, config))
+-			break;
+-	}
++	return eq_done ? 0 : -1;
++}
+ 
+-stop:
+-	/* end link training */
+-	ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_DISABLE);
+-	if (ret)
++bool
++nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
++{
++	struct drm_nouveau_private *dev_priv = encoder->dev->dev_private;
++	struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
++	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
++	struct nouveau_connector *nv_connector =
++		nouveau_encoder_connector_get(nv_encoder);
++	struct drm_device *dev = encoder->dev;
++	struct nouveau_i2c_chan *auxch;
++	const u32 bw_list[] = { 270000, 162000, 0 };
++	const u32 *link_bw = bw_list;
++	struct dp_state dp;
++
++	auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
++	if (!auxch)
+ 		return false;
+ 
+-	/* retry at a lower setting, if possible */
+-	if (!ret && !(eq_done && cr_done)) {
+-		NV_DEBUG_KMS(dev, "\twe failed\n");
+-		if (nv_encoder->dp.link_bw != DP_LINK_BW_1_62) {
+-			NV_DEBUG_KMS(dev, "retry link training at low rate\n");
+-			nv_encoder->dp.link_bw = DP_LINK_BW_1_62;
+-			goto train;
+-		}
++	dp.table = nouveau_dp_bios_data(dev, nv_encoder->dcb, &dp.entry);
++	if (!dp.table)
++		return -EINVAL;
++
++	dp.dcb = nv_encoder->dcb;
++	dp.crtc = nv_crtc->index;
++	dp.auxch = auxch->rd;
++	dp.or = nv_encoder->or;
++	dp.link = !(nv_encoder->dcb->sorconf.link & 1);
++	dp.dpcd = nv_encoder->dp.dpcd;
++
++	/* some sinks toggle hotplug in response to some of the actions
++	 * we take during link training (DP_SET_POWER is one), we need
++	 * to ignore them for the moment to avoid races.
++	 */
++	pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false);
++
++	/* enable down-spreading, if possible */
++	if (dp.table[1] >= 16) {
++		u16 script = ROM16(dp.entry[14]);
++		if (nv_encoder->dp.dpcd[3] & 1)
++			script = ROM16(dp.entry[12]);
++
++		nouveau_bios_run_init_table(dev, script, dp.dcb, dp.crtc);
+ 	}
+ 
+-	if (dpe->script1) {
+-		NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
+-		nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1),
+-					    nv_encoder->dcb);
++	/* execute pre-train script from vbios */
++	nouveau_bios_run_init_table(dev, ROM16(dp.entry[6]), dp.dcb, dp.crtc);
++
++	/* start off at highest link rate supported by encoder and display */
++	while (*link_bw > nv_encoder->dp.link_bw)
++		link_bw++;
++
++	while (link_bw[0]) {
++		/* find minimum required lane count at this link rate */
++		dp.link_nr = nv_encoder->dp.link_nr;
++		while ((dp.link_nr >> 1) * link_bw[0] > datarate)
++			dp.link_nr >>= 1;
++
++		/* drop link rate to minimum with this lane count */
++		while ((link_bw[1] * dp.link_nr) > datarate)
++			link_bw++;
++		dp.link_bw = link_bw[0];
++
++		/* program selected link configuration */
++		dp_set_link_config(dev, &dp);
++
++		/* attempt to train the link at this configuration */
++		memset(dp.stat, 0x00, sizeof(dp.stat));
++		if (!dp_link_train_cr(dev, &dp) &&
++		    !dp_link_train_eq(dev, &dp))
++			break;
++
++		/* retry at lower rate */
++		link_bw++;
+ 	}
+ 
+-	/* re-enable hotplug detect */
+-	pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, hpd_state);
++	/* finish link training */
++	dp_set_training_pattern(dev, &dp, DP_TRAINING_PATTERN_DISABLE);
+ 
+-	return eq_done;
++	/* execute post-train script from vbios */
++	nouveau_bios_run_init_table(dev, ROM16(dp.entry[8]), dp.dcb, dp.crtc);
++
++	/* re-enable hotplug detect */
++	pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true);
++	return true;
+ }
+ 
+ bool
+@@ -447,31 +648,34 @@ nouveau_dp_detect(struct drm_encoder *encoder)
+ {
+ 	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ 	struct drm_device *dev = encoder->dev;
+-	uint8_t dpcd[4];
++	struct nouveau_i2c_chan *auxch;
++	u8 *dpcd = nv_encoder->dp.dpcd;
+ 	int ret;
+ 
+-	ret = auxch_rd(encoder, 0x0000, dpcd, 4);
+-	if (ret)
++	auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
++	if (!auxch)
+ 		return false;
+ 
+-	NV_DEBUG_KMS(dev, "encoder: link_bw %d, link_nr %d\n"
+-		      "display: link_bw %d, link_nr %d version 0x%02x\n",
+-		 nv_encoder->dcb->dpconf.link_bw,
+-		 nv_encoder->dcb->dpconf.link_nr,
+-		 dpcd[1], dpcd[2] & 0x0f, dpcd[0]);
++	ret = auxch_tx(dev, auxch->rd, 9, DP_DPCD_REV, dpcd, 8);
++	if (ret)
++		return false;
+ 
+-	nv_encoder->dp.dpcd_version = dpcd[0];
++	nv_encoder->dp.link_bw = 27000 * dpcd[1];
++	nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
+ 
+-	nv_encoder->dp.link_bw = dpcd[1];
+-	if (nv_encoder->dp.link_bw != DP_LINK_BW_1_62 &&
+-	    !nv_encoder->dcb->dpconf.link_bw)
+-		nv_encoder->dp.link_bw = DP_LINK_BW_1_62;
++	NV_DEBUG_KMS(dev, "display: %dx%d dpcd 0x%02x\n",
++		     nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, dpcd[0]);
++	NV_DEBUG_KMS(dev, "encoder: %dx%d\n",
++		     nv_encoder->dcb->dpconf.link_nr,
++		     nv_encoder->dcb->dpconf.link_bw);
+ 
+-	nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
+-	if (nv_encoder->dp.link_nr > nv_encoder->dcb->dpconf.link_nr)
++	if (nv_encoder->dcb->dpconf.link_nr < nv_encoder->dp.link_nr)
+ 		nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr;
++	if (nv_encoder->dcb->dpconf.link_bw < nv_encoder->dp.link_bw)
++		nv_encoder->dp.link_bw = nv_encoder->dcb->dpconf.link_bw;
+ 
+-	nv_encoder->dp.enhanced_frame = (dpcd[2] & DP_ENHANCED_FRAME_CAP);
++	NV_DEBUG_KMS(dev, "maximum: %dx%d\n",
++		     nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
+ 
+ 	return true;
+ }
+@@ -480,105 +684,13 @@ int
+ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
+ 		 uint8_t *data, int data_nr)
+ {
+-	struct drm_device *dev = auxch->dev;
+-	uint32_t tmp, ctrl, stat = 0, data32[4] = {};
+-	int ret = 0, i, index = auxch->rd;
+-
+-	NV_DEBUG_KMS(dev, "ch %d cmd %d addr 0x%x len %d\n", index, cmd, addr, data_nr);
+-
+-	tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd));
+-	nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp | 0x00100000);
+-	tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd));
+-	if (!(tmp & 0x01000000)) {
+-		NV_ERROR(dev, "expected bit 24 == 1, got 0x%08x\n", tmp);
+-		ret = -EIO;
+-		goto out;
+-	}
+-
+-	for (i = 0; i < 3; i++) {
+-		tmp = nv_rd32(dev, NV50_AUXCH_STAT(auxch->rd));
+-		if (tmp & NV50_AUXCH_STAT_STATE_READY)
+-			break;
+-		udelay(100);
+-	}
+-
+-	if (i == 3) {
+-		ret = -EBUSY;
+-		goto out;
+-	}
+-
+-	if (!(cmd & 1)) {
+-		memcpy(data32, data, data_nr);
+-		for (i = 0; i < 4; i++) {
+-			NV_DEBUG_KMS(dev, "wr %d: 0x%08x\n", i, data32[i]);
+-			nv_wr32(dev, NV50_AUXCH_DATA_OUT(index, i), data32[i]);
+-		}
+-	}
+-
+-	nv_wr32(dev, NV50_AUXCH_ADDR(index), addr);
+-	ctrl  = nv_rd32(dev, NV50_AUXCH_CTRL(index));
+-	ctrl &= ~(NV50_AUXCH_CTRL_CMD | NV50_AUXCH_CTRL_LEN);
+-	ctrl |= (cmd << NV50_AUXCH_CTRL_CMD_SHIFT);
+-	ctrl |= ((data_nr - 1) << NV50_AUXCH_CTRL_LEN_SHIFT);
+-
+-	for (i = 0; i < 16; i++) {
+-		nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000);
+-		nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl);
+-		nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x00010000);
+-		if (!nv_wait(dev, NV50_AUXCH_CTRL(index),
+-			     0x00010000, 0x00000000)) {
+-			NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n",
+-				 nv_rd32(dev, NV50_AUXCH_CTRL(index)));
+-			ret = -EBUSY;
+-			goto out;
+-		}
+-
+-		udelay(400);
+-
+-		stat = nv_rd32(dev, NV50_AUXCH_STAT(index));
+-		if ((stat & NV50_AUXCH_STAT_REPLY_AUX) !=
+-			    NV50_AUXCH_STAT_REPLY_AUX_DEFER)
+-			break;
+-	}
+-
+-	if (i == 16) {
+-		NV_ERROR(dev, "auxch DEFER too many times, bailing\n");
+-		ret = -EREMOTEIO;
+-		goto out;
+-	}
+-
+-	if (cmd & 1) {
+-		if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) {
+-			ret = -EREMOTEIO;
+-			goto out;
+-		}
+-
+-		for (i = 0; i < 4; i++) {
+-			data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i));
+-			NV_DEBUG_KMS(dev, "rd %d: 0x%08x\n", i, data32[i]);
+-		}
+-		memcpy(data, data32, data_nr);
+-	}
+-
+-out:
+-	tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd));
+-	nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp & ~0x00100000);
+-	tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd));
+-	if (tmp & 0x01000000) {
+-		NV_ERROR(dev, "expected bit 24 == 0, got 0x%08x\n", tmp);
+-		ret = -EIO;
+-	}
+-
+-	udelay(400);
+-
+-	return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY);
++	return auxch_tx(auxch->dev, auxch->rd, cmd, addr, data, data_nr);
+ }
+ 
+ static int
+ nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+ {
+ 	struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap;
+-	struct drm_device *dev = auxch->dev;
+ 	struct i2c_msg *msg = msgs;
+ 	int ret, mcnt = num;
+ 
+@@ -602,19 +714,6 @@ nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+ 			if (ret < 0)
+ 				return ret;
+ 
+-			switch (ret & NV50_AUXCH_STAT_REPLY_I2C) {
+-			case NV50_AUXCH_STAT_REPLY_I2C_ACK:
+-				break;
+-			case NV50_AUXCH_STAT_REPLY_I2C_NACK:
+-				return -EREMOTEIO;
+-			case NV50_AUXCH_STAT_REPLY_I2C_DEFER:
+-				udelay(100);
+-				continue;
+-			default:
+-				NV_ERROR(dev, "bad auxch reply: 0x%08x\n", ret);
+-				return -EREMOTEIO;
+-			}
+-
+ 			ptr += cnt;
+ 			remaining -= cnt;
+ 		}
+diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
+index b30ddd8..c1e01f3 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
++++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
+@@ -41,7 +41,7 @@ int nouveau_agpmode = -1;
+ module_param_named(agpmode, nouveau_agpmode, int, 0400);
+ 
+ MODULE_PARM_DESC(modeset, "Enable kernel modesetting");
+-static int nouveau_modeset = -1; /* kms */
++int nouveau_modeset = -1;
+ module_param_named(modeset, nouveau_modeset, int, 0400);
+ 
+ MODULE_PARM_DESC(vbios, "Override default VBIOS location");
+diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
+index d7d51de..29837da 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
++++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
+@@ -414,12 +414,13 @@ struct nouveau_gpio_engine {
+ };
+ 
+ struct nouveau_pm_voltage_level {
+-	u8 voltage;
+-	u8 vid;
++	u32 voltage; /* microvolts */
++	u8  vid;
+ };
+ 
+ struct nouveau_pm_voltage {
+ 	bool supported;
++	u8 version;
+ 	u8 vid_mask;
+ 
+ 	struct nouveau_pm_voltage_level *level;
+@@ -428,17 +429,48 @@ struct nouveau_pm_voltage {
+ 
+ struct nouveau_pm_memtiming {
+ 	int id;
+-	u32 reg_100220;
+-	u32 reg_100224;
+-	u32 reg_100228;
+-	u32 reg_10022c;
+-	u32 reg_100230;
+-	u32 reg_100234;
+-	u32 reg_100238;
+-	u32 reg_10023c;
+-	u32 reg_100240;
++	u32 reg_0; /* 0x10f290 on Fermi, 0x100220 for older */
++	u32 reg_1;
++	u32 reg_2;
++	u32 reg_3;
++	u32 reg_4;
++	u32 reg_5;
++	u32 reg_6;
++	u32 reg_7;
++	u32 reg_8;
++	/* To be written to 0x1002c0 */
++	u8 CL;
++	u8 WR;
+ };
+ 
++struct nouveau_pm_tbl_header{
++	u8 version;
++	u8 header_len;
++	u8 entry_cnt;
++	u8 entry_len;
++};
++
++struct nouveau_pm_tbl_entry{
++	u8 tWR;
++	u8 tUNK_1;
++	u8 tCL;
++	u8 tRP;		/* Byte 3 */
++	u8 empty_4;
++	u8 tRAS;	/* Byte 5 */
++	u8 empty_6;
++	u8 tRFC;	/* Byte 7 */
++	u8 empty_8;
++	u8 tRC;		/* Byte 9 */
++	u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14;
++	u8 empty_15,empty_16,empty_17;
++	u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21;
++};
++
++/* nouveau_mem.c */
++void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
++							struct nouveau_pm_tbl_entry *e, uint8_t magic_number,
++							struct nouveau_pm_memtiming *timing);
++
+ #define NOUVEAU_PM_MAX_LEVEL 8
+ struct nouveau_pm_level {
+ 	struct device_attribute dev_attr;
+@@ -448,11 +480,19 @@ struct nouveau_pm_level {
+ 	u32 core;
+ 	u32 memory;
+ 	u32 shader;
+-	u32 unk05;
+-	u32 unk0a;
+-
+-	u8 voltage;
+-	u8 fanspeed;
++	u32 rop;
++	u32 copy;
++	u32 daemon;
++	u32 vdec;
++	u32 unk05;	/* nv50:nva3, roughly.. */
++	u32 unka0;	/* nva3:nvc0 */
++	u32 hub01;	/* nvc0- */
++	u32 hub06;	/* nvc0- */
++	u32 hub07;	/* nvc0- */
++
++	u32 volt_min; /* microvolts */
++	u32 volt_max;
++	u8  fanspeed;
+ 
+ 	u16 memscript;
+ 	struct nouveau_pm_memtiming *timing;
+@@ -496,6 +536,11 @@ struct nouveau_pm_engine {
+ 	void *(*clock_pre)(struct drm_device *, struct nouveau_pm_level *,
+ 			   u32 id, int khz);
+ 	void (*clock_set)(struct drm_device *, void *);
++
++	int  (*clocks_get)(struct drm_device *, struct nouveau_pm_level *);
++	void *(*clocks_pre)(struct drm_device *, struct nouveau_pm_level *);
++	void (*clocks_set)(struct drm_device *, void *);
++
+ 	int (*voltage_get)(struct drm_device *);
+ 	int (*voltage_set)(struct drm_device *, int voltage);
+ 	int (*fanspeed_get)(struct drm_device *);
+@@ -504,7 +549,7 @@ struct nouveau_pm_engine {
+ };
+ 
+ struct nouveau_vram_engine {
+-	struct nouveau_mm *mm;
++	struct nouveau_mm mm;
+ 
+ 	int  (*init)(struct drm_device *);
+ 	void (*takedown)(struct drm_device *dev);
+@@ -623,6 +668,7 @@ enum nouveau_card_type {
+ 	NV_40      = 0x40,
+ 	NV_50      = 0x50,
+ 	NV_C0      = 0xc0,
++	NV_D0      = 0xd0
+ };
+ 
+ struct drm_nouveau_private {
+@@ -633,8 +679,8 @@ struct drm_nouveau_private {
+ 	enum nouveau_card_type card_type;
+ 	/* exact chipset, derived from NV_PMC_BOOT_0 */
+ 	int chipset;
+-	int stepping;
+ 	int flags;
++	u32 crystal;
+ 
+ 	void __iomem *mmio;
+ 
+@@ -721,7 +767,6 @@ struct drm_nouveau_private {
+ 	uint64_t vram_size;
+ 	uint64_t vram_sys_base;
+ 
+-	uint64_t fb_phys;
+ 	uint64_t fb_available_size;
+ 	uint64_t fb_mappable_pages;
+ 	uint64_t fb_aper_free;
+@@ -784,6 +829,7 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo)
+ }
+ 
+ /* nouveau_drv.c */
++extern int nouveau_modeset;
+ extern int nouveau_agpmode;
+ extern int nouveau_duallink;
+ extern int nouveau_uscript_lvds;
+@@ -824,6 +870,8 @@ extern bool nouveau_wait_eq(struct drm_device *, uint64_t timeout,
+ 			    uint32_t reg, uint32_t mask, uint32_t val);
+ extern bool nouveau_wait_ne(struct drm_device *, uint64_t timeout,
+ 			    uint32_t reg, uint32_t mask, uint32_t val);
++extern bool nouveau_wait_cb(struct drm_device *, u64 timeout,
++			    bool (*cond)(void *), void *);
+ extern bool nouveau_wait_for_idle(struct drm_device *);
+ extern int  nouveau_card_init(struct drm_device *);
+ 
+@@ -1006,15 +1054,15 @@ static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector
+ 
+ /* nouveau_backlight.c */
+ #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT
+-extern int nouveau_backlight_init(struct drm_connector *);
+-extern void nouveau_backlight_exit(struct drm_connector *);
++extern int nouveau_backlight_init(struct drm_device *);
++extern void nouveau_backlight_exit(struct drm_device *);
+ #else
+-static inline int nouveau_backlight_init(struct drm_connector *dev)
++static inline int nouveau_backlight_init(struct drm_device *dev)
+ {
+ 	return 0;
+ }
+ 
+-static inline void nouveau_backlight_exit(struct drm_connector *dev) { }
++static inline void nouveau_backlight_exit(struct drm_device *dev) { }
+ #endif
+ 
+ /* nouveau_bios.c */
+@@ -1022,7 +1070,8 @@ extern int nouveau_bios_init(struct drm_device *);
+ extern void nouveau_bios_takedown(struct drm_device *dev);
+ extern int nouveau_run_vbios_init(struct drm_device *);
+ extern void nouveau_bios_run_init_table(struct drm_device *, uint16_t table,
+-					struct dcb_entry *);
++					struct dcb_entry *, int crtc);
++extern void nouveau_bios_init_exec(struct drm_device *, uint16_t table);
+ extern struct dcb_gpio_entry *nouveau_bios_gpio_entry(struct drm_device *,
+ 						      enum dcb_gpio_tag);
+ extern struct dcb_connector_table_entry *
+@@ -1030,11 +1079,8 @@ nouveau_bios_connector_entry(struct drm_device *, int index);
+ extern u32 get_pll_register(struct drm_device *, enum pll_types);
+ extern int get_pll_limits(struct drm_device *, uint32_t limit_match,
+ 			  struct pll_lims *);
+-extern int nouveau_bios_run_display_table(struct drm_device *,
+-					  struct dcb_entry *,
+-					  uint32_t script, int pxclk);
+-extern void *nouveau_bios_dp_table(struct drm_device *, struct dcb_entry *,
+-				   int *length);
++extern int nouveau_bios_run_display_table(struct drm_device *, u16 id, int clk,
++					  struct dcb_entry *, int crtc);
+ extern bool nouveau_bios_fp_mode(struct drm_device *, struct drm_display_mode *);
+ extern uint8_t *nouveau_bios_embedded_edid(struct drm_device *);
+ extern int nouveau_bios_parse_lvds_table(struct drm_device *, int pxclk,
+@@ -1043,6 +1089,7 @@ extern int run_tmds_table(struct drm_device *, struct dcb_entry *,
+ 			  int head, int pxclk);
+ extern int call_lvds_script(struct drm_device *, struct dcb_entry *, int head,
+ 			    enum LVDS_script, int pxclk);
++bool bios_encoder_match(struct dcb_entry *, u32 hash);
+ 
+ /* nouveau_ttm.c */
+ int nouveau_ttm_global_init(struct drm_nouveau_private *);
+@@ -1053,7 +1100,9 @@ int nouveau_ttm_mmap(struct file *, struct vm_area_struct *);
+ int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
+ 		     uint8_t *data, int data_nr);
+ bool nouveau_dp_detect(struct drm_encoder *);
+-bool nouveau_dp_link_train(struct drm_encoder *);
++bool nouveau_dp_link_train(struct drm_encoder *, u32 datarate);
++void nouveau_dp_tu_update(struct drm_device *, int, int, u32, u32);
++u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_entry *, u8 **);
+ 
+ /* nv04_fb.c */
+ extern int  nv04_fb_init(struct drm_device *);
+@@ -1179,8 +1228,8 @@ extern int  nva3_copy_create(struct drm_device *dev);
+ /* nvc0_copy.c */
+ extern int  nvc0_copy_create(struct drm_device *dev, int engine);
+ 
+-/* nv40_mpeg.c */
+-extern int  nv40_mpeg_create(struct drm_device *dev);
++/* nv31_mpeg.c */
++extern int  nv31_mpeg_create(struct drm_device *dev);
+ 
+ /* nv50_mpeg.c */
+ extern int  nv50_mpeg_create(struct drm_device *dev);
+@@ -1265,6 +1314,11 @@ extern int nv04_display_create(struct drm_device *);
+ extern int nv04_display_init(struct drm_device *);
+ extern void nv04_display_destroy(struct drm_device *);
+ 
++/* nvd0_display.c */
++extern int nvd0_display_create(struct drm_device *);
++extern int nvd0_display_init(struct drm_device *);
++extern void nvd0_display_destroy(struct drm_device *);
++
+ /* nv04_crtc.c */
+ extern int nv04_crtc_create(struct drm_device *, int index);
+ 
+@@ -1374,6 +1428,8 @@ int nv50_gpio_init(struct drm_device *dev);
+ void nv50_gpio_fini(struct drm_device *dev);
+ int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
+ int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
++int nvd0_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
++int nvd0_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
+ int  nv50_gpio_irq_register(struct drm_device *, enum dcb_gpio_tag,
+ 			    void (*)(void *, int), void *);
+ void nv50_gpio_irq_unregister(struct drm_device *, enum dcb_gpio_tag,
+@@ -1448,6 +1504,8 @@ static inline void nv_wr08(struct drm_device *dev, unsigned reg, u8 val)
+ 	nouveau_wait_eq(dev, 2000000000ULL, (reg), (mask), (val))
+ #define nv_wait_ne(dev, reg, mask, val) \
+ 	nouveau_wait_ne(dev, 2000000000ULL, (reg), (mask), (val))
++#define nv_wait_cb(dev, func, data) \
++	nouveau_wait_cb(dev, 2000000000ULL, (func), (data))
+ 
+ /* PRAMIN access */
+ static inline u32 nv_ri32(struct drm_device *dev, unsigned offset)
+@@ -1514,6 +1572,7 @@ enum {
+ 	NOUVEAU_REG_DEBUG_RMVIO          = 0x80,
+ 	NOUVEAU_REG_DEBUG_VGAATTR        = 0x100,
+ 	NOUVEAU_REG_DEBUG_EVO            = 0x200,
++	NOUVEAU_REG_DEBUG_AUXCH          = 0x400
+ };
+ 
+ #define NV_REG_DEBUG(type, dev, fmt, arg...) do { \
+diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
+index ae69b61..e5d6e3f 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
++++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
+@@ -49,17 +49,17 @@ struct nouveau_encoder {
+ 
+ 	union {
+ 		struct {
+-			int mc_unknown;
+-			uint32_t unk0;
+-			uint32_t unk1;
+-			int dpcd_version;
++			u8  dpcd[8];
+ 			int link_nr;
+ 			int link_bw;
+-			bool enhanced_frame;
++			u32 datarate;
+ 		} dp;
+ 	};
+ };
+ 
++struct nouveau_encoder *
++find_encoder(struct drm_connector *connector, int type);
++
+ static inline struct nouveau_encoder *nouveau_encoder(struct drm_encoder *enc)
+ {
+ 	struct drm_encoder_slave *slave = to_encoder_slave(enc);
+@@ -83,21 +83,4 @@ nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
+ int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
+ int nv50_dac_create(struct drm_connector *, struct dcb_entry *);
+ 
+-struct bit_displayport_encoder_table {
+-	uint32_t match;
+-	uint8_t  record_nr;
+-	uint8_t  unknown;
+-	uint16_t script0;
+-	uint16_t script1;
+-	uint16_t unknown_table;
+-} __attribute__ ((packed));
+-
+-struct bit_displayport_encoder_table_entry {
+-	uint8_t vs_level;
+-	uint8_t pre_level;
+-	uint8_t reg0;
+-	uint8_t reg1;
+-	uint8_t reg2;
+-} __attribute__ ((packed));
+-
+ #endif /* __NOUVEAU_ENCODER_H__ */
+diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
+index c919cfc..81116cf 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
++++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
+@@ -519,7 +519,7 @@ nouveau_fence_channel_init(struct nouveau_channel *chan)
+ 	if (USE_SEMA(dev) && dev_priv->chipset < 0x84) {
+ 		struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem;
+ 
+-		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
++		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY,
+ 					     mem->start << PAGE_SHIFT,
+ 					     mem->size, NV_MEM_ACCESS_RW,
+ 					     NV_MEM_TARGET_VRAM, &obj);
+diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
+index cb389d0..f6a27fa 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
++++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
+@@ -107,6 +107,13 @@ nv4e_i2c_getsda(void *data)
+ 	return !!((nv_rd32(dev, i2c->rd) >> 16) & 8);
+ }
+ 
++static const uint32_t nv50_i2c_port[] = {
++	0x00e138, 0x00e150, 0x00e168, 0x00e180,
++	0x00e254, 0x00e274, 0x00e764, 0x00e780,
++	0x00e79c, 0x00e7b8
++};
++#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port)
++
+ static int
+ nv50_i2c_getscl(void *data)
+ {
+@@ -130,28 +137,32 @@ static void
+ nv50_i2c_setscl(void *data, int state)
+ {
+ 	struct nouveau_i2c_chan *i2c = data;
+-	struct drm_device *dev = i2c->dev;
+ 
+-	nv_wr32(dev, i2c->wr, 4 | (i2c->data ? 2 : 0) | (state ? 1 : 0));
++	nv_wr32(i2c->dev, i2c->wr, 4 | (i2c->data ? 2 : 0) | (state ? 1 : 0));
+ }
+ 
+ static void
+ nv50_i2c_setsda(void *data, int state)
+ {
+ 	struct nouveau_i2c_chan *i2c = data;
+-	struct drm_device *dev = i2c->dev;
+ 
+-	nv_wr32(dev, i2c->wr,
+-			(nv_rd32(dev, i2c->rd) & 1) | 4 | (state ? 2 : 0));
++	nv_mask(i2c->dev, i2c->wr, 0x00000006, 4 | (state ? 2 : 0));
+ 	i2c->data = state;
+ }
+ 
+-static const uint32_t nv50_i2c_port[] = {
+-	0x00e138, 0x00e150, 0x00e168, 0x00e180,
+-	0x00e254, 0x00e274, 0x00e764, 0x00e780,
+-	0x00e79c, 0x00e7b8
+-};
+-#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port)
++static int
++nvd0_i2c_getscl(void *data)
++{
++	struct nouveau_i2c_chan *i2c = data;
++	return !!(nv_rd32(i2c->dev, i2c->rd) & 0x10);
++}
++
++static int
++nvd0_i2c_getsda(void *data)
++{
++	struct nouveau_i2c_chan *i2c = data;
++	return !!(nv_rd32(i2c->dev, i2c->rd) & 0x20);
++}
+ 
+ int
+ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
+@@ -163,7 +174,8 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
+ 	if (entry->chan)
+ 		return -EEXIST;
+ 
+-	if (dev_priv->card_type >= NV_50 && entry->read >= NV50_I2C_PORTS) {
++	if (dev_priv->card_type >= NV_50 &&
++	    dev_priv->card_type <= NV_C0 && entry->read >= NV50_I2C_PORTS) {
+ 		NV_ERROR(dev, "unknown i2c port %d\n", entry->read);
+ 		return -EINVAL;
+ 	}
+@@ -192,10 +204,17 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
+ 	case 5:
+ 		i2c->bit.setsda = nv50_i2c_setsda;
+ 		i2c->bit.setscl = nv50_i2c_setscl;
+-		i2c->bit.getsda = nv50_i2c_getsda;
+-		i2c->bit.getscl = nv50_i2c_getscl;
+-		i2c->rd = nv50_i2c_port[entry->read];
+-		i2c->wr = i2c->rd;
++		if (dev_priv->card_type < NV_D0) {
++			i2c->bit.getsda = nv50_i2c_getsda;
++			i2c->bit.getscl = nv50_i2c_getscl;
++			i2c->rd = nv50_i2c_port[entry->read];
++			i2c->wr = i2c->rd;
++		} else {
++			i2c->bit.getsda = nvd0_i2c_getsda;
++			i2c->bit.getscl = nvd0_i2c_getscl;
++			i2c->rd = 0x00d014 + (entry->read * 0x20);
++			i2c->wr = i2c->rd;
++		}
+ 		break;
+ 	case 6:
+ 		i2c->rd = entry->read;
+@@ -267,7 +286,10 @@ nouveau_i2c_find(struct drm_device *dev, int index)
+ 			val  = 0xe001;
+ 		}
+ 
+-		nv_wr32(dev, reg, (nv_rd32(dev, reg) & ~0xf003) | val);
++		/* nfi, but neither auxch or i2c work if it's 1 */
++		nv_mask(dev, reg + 0x0c, 0x00000001, 0x00000000);
++		/* nfi, but switches auxch vs normal i2c */
++		nv_mask(dev, reg + 0x00, 0x0000f003, val);
+ 	}
+ 
+ 	if (!i2c->chan && nouveau_i2c_init(dev, i2c, index))
+diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
+index f9ae2fc..36bec48 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
++++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
+@@ -408,8 +408,6 @@ nouveau_mem_vram_init(struct drm_device *dev)
+ 	if (ret)
+ 		return ret;
+ 
+-	dev_priv->fb_phys = pci_resource_start(dev->pdev, 1);
+-
+ 	ret = nouveau_ttm_global_init(dev_priv);
+ 	if (ret)
+ 		return ret;
+@@ -504,35 +502,146 @@ nouveau_mem_gart_init(struct drm_device *dev)
+ 	return 0;
+ }
+ 
++/* XXX: For now a dummy. More samples required, possibly even a card
++ * Called from nouveau_perf.c */
++void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
++							struct nouveau_pm_tbl_entry *e, uint8_t magic_number,
++							struct nouveau_pm_memtiming *timing) {
++
++	NV_DEBUG(dev,"Timing entry format unknown, please contact nouveau developers");
++}
++
++void nv40_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
++							struct nouveau_pm_tbl_entry *e, uint8_t magic_number,
++							struct nouveau_pm_memtiming *timing) {
++
++	timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP);
++
++	/* XXX: I don't trust the -1's and +1's... they must come
++	 *      from somewhere! */
++	timing->reg_1 = (e->tWR + 2 + magic_number) << 24 |
++				  1 << 16 |
++				  (e->tUNK_1 + 2 + magic_number) << 8 |
++				  (e->tCL + 2 - magic_number);
++	timing->reg_2 = (magic_number << 24 | e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10);
++	timing->reg_2 |= 0x20200000;
++
++	NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", timing->id,
++		 timing->reg_0, timing->reg_1,timing->reg_2);
++}
++
++void nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P, struct nouveau_pm_tbl_header *hdr,
++							struct nouveau_pm_tbl_entry *e, uint8_t magic_number,struct nouveau_pm_memtiming *timing) {
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++
++	uint8_t unk18 = 1,
++		unk19 = 1,
++		unk20 = 0,
++		unk21 = 0;
++
++	switch (min(hdr->entry_len, (u8) 22)) {
++	case 22:
++		unk21 = e->tUNK_21;
++	case 21:
++		unk20 = e->tUNK_20;
++	case 20:
++		unk19 = e->tUNK_19;
++	case 19:
++		unk18 = e->tUNK_18;
++		break;
++	}
++
++	timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP);
++
++	/* XXX: I don't trust the -1's and +1's... they must come
++	 *      from somewhere! */
++	timing->reg_1 = (e->tWR + unk19 + 1 + magic_number) << 24 |
++				  max(unk18, (u8) 1) << 16 |
++				  (e->tUNK_1 + unk19 + 1 + magic_number) << 8;
++	if (dev_priv->chipset == 0xa8) {
++		timing->reg_1 |= (e->tCL - 1);
++	} else {
++		timing->reg_1 |= (e->tCL + 2 - magic_number);
++	}
++	timing->reg_2 = (e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10);
++
++	timing->reg_5 = (e->tRAS << 24 | e->tRC);
++	timing->reg_5 += max(e->tUNK_10, e->tUNK_11) << 16;
++
++	if (P->version == 1) {
++		timing->reg_2 |= magic_number << 24;
++		timing->reg_3 = (0x14 + e->tCL) << 24 |
++						0x16 << 16 |
++						(e->tCL - 1) << 8 |
++						(e->tCL - 1);
++		timing->reg_4 = (nv_rd32(dev,0x10022c) & 0xffff0000) | e->tUNK_13 << 8  | e->tUNK_13;
++		timing->reg_5 |= (e->tCL + 2) << 8;
++		timing->reg_7 = 0x4000202 | (e->tCL - 1) << 16;
++	} else {
++		timing->reg_2 |= (unk19 - 1) << 24;
++		/* XXX: reg_10022c for recentish cards pretty much unknown*/
++		timing->reg_3 = e->tCL - 1;
++		timing->reg_4 = (unk20 << 24 | unk21 << 16 |
++							e->tUNK_13 << 8  | e->tUNK_13);
++		/* XXX: +6? */
++		timing->reg_5 |= (unk19 + 6) << 8;
++
++		/* XXX: reg_10023c currently unknown
++		 * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
++		timing->reg_7 = 0x202;
++	}
++
++	NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", timing->id,
++		 timing->reg_0, timing->reg_1,
++		 timing->reg_2, timing->reg_3);
++	NV_DEBUG(dev, "         230: %08x %08x %08x %08x\n",
++		 timing->reg_4, timing->reg_5,
++		 timing->reg_6, timing->reg_7);
++	NV_DEBUG(dev, "         240: %08x\n", timing->reg_8);
++}
++
++void nvc0_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
++							struct nouveau_pm_tbl_entry *e, struct nouveau_pm_memtiming *timing) {
++	timing->reg_0 = (e->tRC << 24 | (e->tRFC & 0x7f) << 17 | e->tRAS << 8 | e->tRP);
++	timing->reg_1 = (nv_rd32(dev,0x10f294) & 0xff000000) | (e->tUNK_11&0x0f) << 20 | (e->tUNK_19 << 7) | (e->tCL & 0x0f);
++	timing->reg_2 = (nv_rd32(dev,0x10f298) & 0xff0000ff) | e->tWR << 16 | e->tUNK_1 << 8;
++	timing->reg_3 = e->tUNK_20 << 9 | e->tUNK_13;
++	timing->reg_4 = (nv_rd32(dev,0x10f2a0) & 0xfff000ff) | e->tUNK_12 << 15;
++	NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", timing->id,
++		 timing->reg_0, timing->reg_1,
++		 timing->reg_2, timing->reg_3);
++	NV_DEBUG(dev, "         2a0: %08x %08x %08x %08x\n",
++		 timing->reg_4, timing->reg_5,
++		 timing->reg_6, timing->reg_7);
++}
++
++/**
++ * Processes the Memory Timing BIOS table, stores generated
++ * register values
++ * @pre init scripts were run, memtiming regs are initialized
++ */
+ void
+ nouveau_mem_timing_init(struct drm_device *dev)
+ {
+-	/* cards < NVC0 only */
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ 	struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
+ 	struct nvbios *bios = &dev_priv->vbios;
+ 	struct bit_entry P;
+-	u8 tUNK_0, tUNK_1, tUNK_2;
+-	u8 tRP;		/* Byte 3 */
+-	u8 tRAS;	/* Byte 5 */
+-	u8 tRFC;	/* Byte 7 */
+-	u8 tRC;		/* Byte 9 */
+-	u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14;
+-	u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21;
+-	u8 magic_number = 0; /* Yeah... sorry*/
+-	u8 *mem = NULL, *entry;
+-	int i, recordlen, entries;
++	struct nouveau_pm_tbl_header *hdr = NULL;
++	uint8_t magic_number;
++	u8 *entry;
++	int i;
+ 
+ 	if (bios->type == NVBIOS_BIT) {
+ 		if (bit_table(dev, 'P', &P))
+ 			return;
+ 
+ 		if (P.version == 1)
+-			mem = ROMPTR(bios, P.data[4]);
++			hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[4]);
+ 		else
+ 		if (P.version == 2)
+-			mem = ROMPTR(bios, P.data[8]);
++			hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[8]);
+ 		else {
+ 			NV_WARN(dev, "unknown mem for BIT P %d\n", P.version);
+ 		}
+@@ -541,150 +650,56 @@ nouveau_mem_timing_init(struct drm_device *dev)
+ 		return;
+ 	}
+ 
+-	if (!mem) {
++	if (!hdr) {
+ 		NV_DEBUG(dev, "memory timing table pointer invalid\n");
+ 		return;
+ 	}
+ 
+-	if (mem[0] != 0x10) {
+-		NV_WARN(dev, "memory timing table 0x%02x unknown\n", mem[0]);
++	if (hdr->version != 0x10) {
++		NV_WARN(dev, "memory timing table 0x%02x unknown\n", hdr->version);
+ 		return;
+ 	}
+ 
+ 	/* validate record length */
+-	entries   = mem[2];
+-	recordlen = mem[3];
+-	if (recordlen < 15) {
+-		NV_ERROR(dev, "mem timing table length unknown: %d\n", mem[3]);
++	if (hdr->entry_len < 15) {
++		NV_ERROR(dev, "mem timing table length unknown: %d\n", hdr->entry_len);
+ 		return;
+ 	}
+ 
+ 	/* parse vbios entries into common format */
+ 	memtimings->timing =
+-		kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL);
++		kcalloc(hdr->entry_cnt, sizeof(*memtimings->timing), GFP_KERNEL);
+ 	if (!memtimings->timing)
+ 		return;
+ 
+ 	/* Get "some number" from the timing reg for NV_40 and NV_50
+-	 * Used in calculations later */
+-	if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) {
++	 * Used in calculations later... source unknown */
++	magic_number = 0;
++	if (P.version == 1) {
+ 		magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24;
+ 	}
+ 
+-	entry = mem + mem[1];
+-	for (i = 0; i < entries; i++, entry += recordlen) {
++	entry = (u8*) hdr + hdr->header_len;
++	for (i = 0; i < hdr->entry_cnt; i++, entry += hdr->entry_len) {
+ 		struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i];
+ 		if (entry[0] == 0)
+ 			continue;
+ 
+-		tUNK_18 = 1;
+-		tUNK_19 = 1;
+-		tUNK_20 = 0;
+-		tUNK_21 = 0;
+-		switch (min(recordlen, 22)) {
+-		case 22:
+-			tUNK_21 = entry[21];
+-		case 21:
+-			tUNK_20 = entry[20];
+-		case 20:
+-			tUNK_19 = entry[19];
+-		case 19:
+-			tUNK_18 = entry[18];
+-		default:
+-			tUNK_0  = entry[0];
+-			tUNK_1  = entry[1];
+-			tUNK_2  = entry[2];
+-			tRP     = entry[3];
+-			tRAS    = entry[5];
+-			tRFC    = entry[7];
+-			tRC     = entry[9];
+-			tUNK_10 = entry[10];
+-			tUNK_11 = entry[11];
+-			tUNK_12 = entry[12];
+-			tUNK_13 = entry[13];
+-			tUNK_14 = entry[14];
+-			break;
+-		}
+-
+-		timing->reg_100220 = (tRC << 24 | tRFC << 16 | tRAS << 8 | tRP);
+-
+-		/* XXX: I don't trust the -1's and +1's... they must come
+-		 *      from somewhere! */
+-		timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 |
+-				      max(tUNK_18, (u8) 1) << 16 |
+-				      (tUNK_1 + tUNK_19 + 1 + magic_number) << 8;
+-		if (dev_priv->chipset == 0xa8) {
+-			timing->reg_100224 |= (tUNK_2 - 1);
+-		} else {
+-			timing->reg_100224 |= (tUNK_2 + 2 - magic_number);
+-		}
+-
+-		timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
+-		if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa)
+-			timing->reg_100228 |= (tUNK_19 - 1) << 24;
+-		else
+-			timing->reg_100228 |= magic_number << 24;
+-
+-		if (dev_priv->card_type == NV_40) {
+-			/* NV40: don't know what the rest of the regs are..
+-			 * And don't need to know either */
+-			timing->reg_100228 |= 0x20200000;
+-		} else if (dev_priv->card_type >= NV_50) {
+-			if (dev_priv->chipset < 0x98 ||
+-			    (dev_priv->chipset == 0x98 &&
+-			     dev_priv->stepping <= 0xa1)) {
+-				timing->reg_10022c = (0x14 + tUNK_2) << 24 |
+-						     0x16 << 16 |
+-						     (tUNK_2 - 1) << 8 |
+-						     (tUNK_2 - 1);
+-			} else {
+-				/* XXX: reg_10022c for recentish cards */
+-				timing->reg_10022c = tUNK_2 - 1;
+-			}
+-
+-			timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
+-						  tUNK_13 << 8  | tUNK_13);
+-
+-			timing->reg_100234 = (tRAS << 24 | tRC);
+-			timing->reg_100234 += max(tUNK_10, tUNK_11) << 16;
+-
+-			if (dev_priv->chipset < 0x98 ||
+-			    (dev_priv->chipset == 0x98 &&
+-			     dev_priv->stepping <= 0xa1)) {
+-				timing->reg_100234 |= (tUNK_2 + 2) << 8;
+-			} else {
+-				/* XXX: +6? */
+-				timing->reg_100234 |= (tUNK_19 + 6) << 8;
+-			}
+-
+-			/* XXX; reg_100238
+-			 * reg_100238: 0x00?????? */
+-			timing->reg_10023c = 0x202;
+-			if (dev_priv->chipset < 0x98 ||
+-			    (dev_priv->chipset == 0x98 &&
+-			     dev_priv->stepping <= 0xa1)) {
+-				timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16;
+-			} else {
+-				/* XXX: reg_10023c
+-				 * currently unknown
+-				 * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
+-			}
+-
+-			/* XXX: reg_100240? */
+-		}
+ 		timing->id = i;
+-
+-		NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
+-			 timing->reg_100220, timing->reg_100224,
+-			 timing->reg_100228, timing->reg_10022c);
+-		NV_DEBUG(dev, "         230: %08x %08x %08x %08x\n",
+-			 timing->reg_100230, timing->reg_100234,
+-			 timing->reg_100238, timing->reg_10023c);
+-		NV_DEBUG(dev, "         240: %08x\n", timing->reg_100240);
++		timing->WR = entry[0];
++		timing->CL = entry[2];
++
++		if(dev_priv->card_type <= NV_40) {
++			nv40_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]);
++		} else if(dev_priv->card_type == NV_50){
++			nv50_mem_timing_entry(dev,&P,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]);
++		} else if(dev_priv->card_type == NV_C0) {
++			nvc0_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,&pm->memtimings.timing[i]);
++		}
+ 	}
+ 
+-	memtimings->nr_timing = entries;
+-	memtimings->supported = (dev_priv->chipset <= 0x98);
++	memtimings->nr_timing = hdr->entry_cnt;
++	memtimings->supported = P.version == 1;
+ }
+ 
+ void
+@@ -693,7 +708,10 @@ nouveau_mem_timing_fini(struct drm_device *dev)
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 	struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings;
+ 
+-	kfree(mem->timing);
++	if(mem->timing) {
++		kfree(mem->timing);
++		mem->timing = NULL;
++	}
+ }
+ 
+ static int
+diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.c b/drivers/gpu/drm/nouveau/nouveau_mm.c
+index 1640dec..b29ffb3 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_mm.c
++++ b/drivers/gpu/drm/nouveau/nouveau_mm.c
+@@ -27,7 +27,7 @@
+ #include "nouveau_mm.h"
+ 
+ static inline void
+-region_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a)
++region_put(struct nouveau_mm *mm, struct nouveau_mm_node *a)
+ {
+ 	list_del(&a->nl_entry);
+ 	list_del(&a->fl_entry);
+@@ -35,7 +35,7 @@ region_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a)
+ }
+ 
+ static struct nouveau_mm_node *
+-region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size)
++region_split(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
+ {
+ 	struct nouveau_mm_node *b;
+ 
+@@ -57,33 +57,33 @@ region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size)
+ 	return b;
+ }
+ 
+-#define node(root, dir) ((root)->nl_entry.dir == &rmm->nodes) ? NULL : \
++#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \
+ 	list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
+ 
+ void
+-nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this)
++nouveau_mm_put(struct nouveau_mm *mm, struct nouveau_mm_node *this)
+ {
+ 	struct nouveau_mm_node *prev = node(this, prev);
+ 	struct nouveau_mm_node *next = node(this, next);
+ 
+-	list_add(&this->fl_entry, &rmm->free);
++	list_add(&this->fl_entry, &mm->free);
+ 	this->type = 0;
+ 
+ 	if (prev && prev->type == 0) {
+ 		prev->length += this->length;
+-		region_put(rmm, this);
++		region_put(mm, this);
+ 		this = prev;
+ 	}
+ 
+ 	if (next && next->type == 0) {
+ 		next->offset  = this->offset;
+ 		next->length += this->length;
+-		region_put(rmm, this);
++		region_put(mm, this);
+ 	}
+ }
+ 
+ int
+-nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc,
++nouveau_mm_get(struct nouveau_mm *mm, int type, u32 size, u32 size_nc,
+ 	       u32 align, struct nouveau_mm_node **pnode)
+ {
+ 	struct nouveau_mm_node *prev, *this, *next;
+@@ -92,17 +92,17 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc,
+ 	u32 splitoff;
+ 	u32 s, e;
+ 
+-	list_for_each_entry(this, &rmm->free, fl_entry) {
++	list_for_each_entry(this, &mm->free, fl_entry) {
+ 		e = this->offset + this->length;
+ 		s = this->offset;
+ 
+ 		prev = node(this, prev);
+ 		if (prev && prev->type != type)
+-			s = roundup(s, rmm->block_size);
++			s = roundup(s, mm->block_size);
+ 
+ 		next = node(this, next);
+ 		if (next && next->type != type)
+-			e = rounddown(e, rmm->block_size);
++			e = rounddown(e, mm->block_size);
+ 
+ 		s  = (s + align_mask) & ~align_mask;
+ 		e &= ~align_mask;
+@@ -110,10 +110,10 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc,
+ 			continue;
+ 
+ 		splitoff = s - this->offset;
+-		if (splitoff && !region_split(rmm, this, splitoff))
++		if (splitoff && !region_split(mm, this, splitoff))
+ 			return -ENOMEM;
+ 
+-		this = region_split(rmm, this, min(size, e - s));
++		this = region_split(mm, this, min(size, e - s));
+ 		if (!this)
+ 			return -ENOMEM;
+ 
+@@ -127,52 +127,49 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc,
+ }
+ 
+ int
+-nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block)
++nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
+ {
+-	struct nouveau_mm *rmm;
+-	struct nouveau_mm_node *heap;
++	struct nouveau_mm_node *node;
++
++	if (block) {
++		mutex_init(&mm->mutex);
++		INIT_LIST_HEAD(&mm->nodes);
++		INIT_LIST_HEAD(&mm->free);
++		mm->block_size = block;
++		mm->heap_nodes = 0;
++	}
+ 
+-	heap = kzalloc(sizeof(*heap), GFP_KERNEL);
+-	if (!heap)
++	node = kzalloc(sizeof(*node), GFP_KERNEL);
++	if (!node)
+ 		return -ENOMEM;
+-	heap->offset = roundup(offset, block);
+-	heap->length = rounddown(offset + length, block) - heap->offset;
++	node->offset = roundup(offset, mm->block_size);
++	node->length = rounddown(offset + length, mm->block_size) - node->offset;
+ 
+-	rmm = kzalloc(sizeof(*rmm), GFP_KERNEL);
+-	if (!rmm) {
+-		kfree(heap);
+-		return -ENOMEM;
+-	}
+-	rmm->block_size = block;
+-	mutex_init(&rmm->mutex);
+-	INIT_LIST_HEAD(&rmm->nodes);
+-	INIT_LIST_HEAD(&rmm->free);
+-	list_add(&heap->nl_entry, &rmm->nodes);
+-	list_add(&heap->fl_entry, &rmm->free);
+-
+-	*prmm = rmm;
++	list_add_tail(&node->nl_entry, &mm->nodes);
++	list_add_tail(&node->fl_entry, &mm->free);
++	mm->heap_nodes++;
+ 	return 0;
+ }
+ 
+ int
+-nouveau_mm_fini(struct nouveau_mm **prmm)
++nouveau_mm_fini(struct nouveau_mm *mm)
+ {
+-	struct nouveau_mm *rmm = *prmm;
+ 	struct nouveau_mm_node *node, *heap =
+-		list_first_entry(&rmm->nodes, struct nouveau_mm_node, nl_entry);
+-
+-	if (!list_is_singular(&rmm->nodes)) {
+-		printk(KERN_ERR "nouveau_mm not empty at destroy time!\n");
+-		list_for_each_entry(node, &rmm->nodes, nl_entry) {
+-			printk(KERN_ERR "0x%02x: 0x%08x 0x%08x\n",
+-			       node->type, node->offset, node->length);
++		list_first_entry(&mm->nodes, struct nouveau_mm_node, nl_entry);
++	int nodes = 0;
++
++	list_for_each_entry(node, &mm->nodes, nl_entry) {
++		if (nodes++ == mm->heap_nodes) {
++			printk(KERN_ERR "nouveau_mm in use at destroy time!\n");
++			list_for_each_entry(node, &mm->nodes, nl_entry) {
++				printk(KERN_ERR "0x%02x: 0x%08x 0x%08x\n",
++				       node->type, node->offset, node->length);
++			}
++			WARN_ON(1);
++			return -EBUSY;
+ 		}
+-		WARN_ON(1);
+-		return -EBUSY;
+ 	}
+ 
+ 	kfree(heap);
+-	kfree(rmm);
+-	*prmm = NULL;
+ 	return 0;
+ }
+diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.h b/drivers/gpu/drm/nouveau/nouveau_mm.h
+index b9c016d..57a600c 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_mm.h
++++ b/drivers/gpu/drm/nouveau/nouveau_mm.h
+@@ -42,10 +42,11 @@ struct nouveau_mm {
+ 	struct mutex mutex;
+ 
+ 	u32 block_size;
++	int heap_nodes;
+ };
+ 
+-int  nouveau_mm_init(struct nouveau_mm **, u32 offset, u32 length, u32 block);
+-int  nouveau_mm_fini(struct nouveau_mm **);
++int  nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block);
++int  nouveau_mm_fini(struct nouveau_mm *);
+ int  nouveau_mm_pre(struct nouveau_mm *);
+ int  nouveau_mm_get(struct nouveau_mm *, int type, u32 size, u32 size_nc,
+ 		    u32 align, struct nouveau_mm_node **);
+diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
+index 159b7c4..02222c5 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_object.c
++++ b/drivers/gpu/drm/nouveau/nouveau_object.c
+@@ -693,6 +693,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
+ static int
+ nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm)
+ {
++	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ 	struct drm_device *dev = chan->dev;
+ 	struct nouveau_gpuobj *pgd = NULL;
+ 	struct nouveau_vm_pgd *vpgd;
+@@ -722,6 +723,9 @@ nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm)
+ 	nv_wo32(chan->ramin, 0x020c, 0x000000ff);
+ 
+ 	/* map display semaphore buffers into channel's vm */
++	if (dev_priv->card_type >= NV_D0)
++		return 0;
++
+ 	for (i = 0; i < 2; i++) {
+ 		struct nv50_display_crtc *dispc = &nv50_display(dev)->crtc[i];
+ 
+@@ -746,7 +750,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
+ 	int ret, i;
+ 
+ 	NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
+-	if (dev_priv->card_type == NV_C0)
++	if (dev_priv->card_type >= NV_C0)
+ 		return nvc0_gpuobj_channel_init(chan, vm);
+ 
+ 	/* Allocate a chunk of memory for per-channel object storage */
+@@ -793,7 +797,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
+ 			return ret;
+ 
+ 		/* dma objects for display sync channel semaphore blocks */
+-		for (i = 0; i < 2; i++) {
++		for (i = 0; i < dev->mode_config.num_crtc; i++) {
+ 			struct nouveau_gpuobj *sem = NULL;
+ 			struct nv50_display_crtc *dispc =
+ 				&nv50_display(dev)->crtc[i];
+@@ -875,18 +879,18 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
+ 
+ 	NV_DEBUG(dev, "ch%d\n", chan->id);
+ 
+-	if (dev_priv->card_type >= NV_50) {
++	if (dev_priv->card_type >= NV_50 && dev_priv->card_type <= NV_C0) {
+ 		struct nv50_display *disp = nv50_display(dev);
+ 
+-		for (i = 0; i < 2; i++) {
++		for (i = 0; i < dev->mode_config.num_crtc; i++) {
+ 			struct nv50_display_crtc *dispc = &disp->crtc[i];
+ 			nouveau_bo_vma_del(dispc->sem.bo, &chan->dispc_vma[i]);
+ 		}
+-
+-		nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd);
+-		nouveau_gpuobj_ref(NULL, &chan->vm_pd);
+ 	}
+ 
++	nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd);
++	nouveau_gpuobj_ref(NULL, &chan->vm_pd);
++
+ 	if (drm_mm_initialized(&chan->ramin_heap))
+ 		drm_mm_takedown(&chan->ramin_heap);
+ 	nouveau_gpuobj_ref(NULL, &chan->ramin);
+diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
+index ef9dec0..9f178aa 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_perf.c
++++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
+@@ -127,13 +127,57 @@ nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P,
+ 
+ 	entry += ramcfg * recordlen;
+ 	if (entry[1] >= pm->memtimings.nr_timing) {
+-		NV_WARN(dev, "timingset %d does not exist\n", entry[1]);
++		if (entry[1] != 0xff)
++			NV_WARN(dev, "timingset %d does not exist\n", entry[1]);
+ 		return NULL;
+ 	}
+ 
+ 	return &pm->memtimings.timing[entry[1]];
+ }
+ 
++static void
++nouveau_perf_voltage(struct drm_device *dev, struct bit_entry *P,
++		     struct nouveau_pm_level *perflvl)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nvbios *bios = &dev_priv->vbios;
++	u8 *vmap;
++	int id;
++
++	id = perflvl->volt_min;
++	perflvl->volt_min = 0;
++
++	/* boards using voltage table version <0x40 store the voltage
++	 * level directly in the perflvl entry as a multiple of 10mV
++	 */
++	if (dev_priv->engine.pm.voltage.version < 0x40) {
++		perflvl->volt_min = id * 10000;
++		perflvl->volt_max = perflvl->volt_min;
++		return;
++	}
++
++	/* on newer ones, the perflvl stores an index into yet another
++	 * vbios table containing a min/max voltage value for the perflvl
++	 */
++	if (P->version != 2 || P->length < 34) {
++		NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n",
++			 P->version, P->length);
++		return;
++	}
++
++	vmap = ROMPTR(bios, P->data[32]);
++	if (!vmap) {
++		NV_DEBUG(dev, "volt map table pointer invalid\n");
++		return;
++	}
++
++	if (id < vmap[3]) {
++		vmap += vmap[1] + (vmap[2] * id);
++		perflvl->volt_min = ROM32(vmap[0]);
++		perflvl->volt_max = ROM32(vmap[4]);
++	}
++}
++
+ void
+ nouveau_perf_init(struct drm_device *dev)
+ {
+@@ -141,6 +185,8 @@ nouveau_perf_init(struct drm_device *dev)
+ 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ 	struct nvbios *bios = &dev_priv->vbios;
+ 	struct bit_entry P;
++	struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
++	struct nouveau_pm_tbl_header mt_hdr;
+ 	u8 version, headerlen, recordlen, entries;
+ 	u8 *perf, *entry;
+ 	int vid, i;
+@@ -188,6 +234,22 @@ nouveau_perf_init(struct drm_device *dev)
+ 	}
+ 
+ 	entry = perf + headerlen;
++
++	/* For version 0x15, initialize memtiming table */
++	if(version == 0x15) {
++		memtimings->timing =
++				kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL);
++		if(!memtimings) {
++			NV_WARN(dev,"Could not allocate memtiming table\n");
++			return;
++		}
++
++		mt_hdr.entry_cnt = entries;
++		mt_hdr.entry_len = 14;
++		mt_hdr.version = version;
++		mt_hdr.header_len = 4;
++	}
++
+ 	for (i = 0; i < entries; i++) {
+ 		struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
+ 
+@@ -203,7 +265,8 @@ nouveau_perf_init(struct drm_device *dev)
+ 		case 0x13:
+ 		case 0x15:
+ 			perflvl->fanspeed = entry[55];
+-			perflvl->voltage = (recordlen > 56) ? entry[56] : 0;
++			if (recordlen > 56)
++				perflvl->volt_min = entry[56];
+ 			perflvl->core = ROM32(entry[1]) * 10;
+ 			perflvl->memory = ROM32(entry[5]) * 20;
+ 			break;
+@@ -211,9 +274,10 @@ nouveau_perf_init(struct drm_device *dev)
+ 		case 0x23:
+ 		case 0x24:
+ 			perflvl->fanspeed = entry[4];
+-			perflvl->voltage = entry[5];
+-			perflvl->core = ROM16(entry[6]) * 1000;
+-
++			perflvl->volt_min = entry[5];
++			perflvl->shader = ROM16(entry[6]) * 1000;
++			perflvl->core = perflvl->shader;
++			perflvl->core += (signed char)entry[8] * 1000;
+ 			if (dev_priv->chipset == 0x49 ||
+ 			    dev_priv->chipset == 0x4b)
+ 				perflvl->memory = ROM16(entry[11]) * 1000;
+@@ -223,7 +287,7 @@ nouveau_perf_init(struct drm_device *dev)
+ 			break;
+ 		case 0x25:
+ 			perflvl->fanspeed = entry[4];
+-			perflvl->voltage = entry[5];
++			perflvl->volt_min = entry[5];
+ 			perflvl->core = ROM16(entry[6]) * 1000;
+ 			perflvl->shader = ROM16(entry[10]) * 1000;
+ 			perflvl->memory = ROM16(entry[12]) * 1000;
+@@ -232,7 +296,7 @@ nouveau_perf_init(struct drm_device *dev)
+ 			perflvl->memscript = ROM16(entry[2]);
+ 		case 0x35:
+ 			perflvl->fanspeed = entry[6];
+-			perflvl->voltage = entry[7];
++			perflvl->volt_min = entry[7];
+ 			perflvl->core = ROM16(entry[8]) * 1000;
+ 			perflvl->shader = ROM16(entry[10]) * 1000;
+ 			perflvl->memory = ROM16(entry[12]) * 1000;
+@@ -240,30 +304,34 @@ nouveau_perf_init(struct drm_device *dev)
+ 			perflvl->unk05 = ROM16(entry[16]) * 1000;
+ 			break;
+ 		case 0x40:
+-#define subent(n) entry[perf[2] + ((n) * perf[3])]
++#define subent(n) (ROM16(entry[perf[2] + ((n) * perf[3])]) & 0xfff) * 1000
+ 			perflvl->fanspeed = 0; /*XXX*/
+-			perflvl->voltage = entry[2];
++			perflvl->volt_min = entry[2];
+ 			if (dev_priv->card_type == NV_50) {
+-				perflvl->core = ROM16(subent(0)) & 0xfff;
+-				perflvl->shader = ROM16(subent(1)) & 0xfff;
+-				perflvl->memory = ROM16(subent(2)) & 0xfff;
++				perflvl->core   = subent(0);
++				perflvl->shader = subent(1);
++				perflvl->memory = subent(2);
++				perflvl->vdec   = subent(3);
++				perflvl->unka0  = subent(4);
+ 			} else {
+-				perflvl->shader = ROM16(subent(3)) & 0xfff;
++				perflvl->hub06  = subent(0);
++				perflvl->hub01  = subent(1);
++				perflvl->copy   = subent(2);
++				perflvl->shader = subent(3);
++				perflvl->rop    = subent(4);
++				perflvl->memory = subent(5);
++				perflvl->vdec   = subent(6);
++				perflvl->daemon = subent(10);
++				perflvl->hub07  = subent(11);
+ 				perflvl->core   = perflvl->shader / 2;
+-				perflvl->unk0a  = ROM16(subent(4)) & 0xfff;
+-				perflvl->memory = ROM16(subent(5)) & 0xfff;
+ 			}
+-
+-			perflvl->core *= 1000;
+-			perflvl->shader *= 1000;
+-			perflvl->memory *= 1000;
+-			perflvl->unk0a *= 1000;
+ 			break;
+ 		}
+ 
+ 		/* make sure vid is valid */
+-		if (pm->voltage.supported && perflvl->voltage) {
+-			vid = nouveau_volt_vid_lookup(dev, perflvl->voltage);
++		nouveau_perf_voltage(dev, &P, perflvl);
++		if (pm->voltage.supported && perflvl->volt_min) {
++			vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min);
+ 			if (vid < 0) {
+ 				NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i);
+ 				entry += recordlen;
+@@ -272,7 +340,11 @@ nouveau_perf_init(struct drm_device *dev)
+ 		}
+ 
+ 		/* get the corresponding memory timings */
+-		if (version > 0x15) {
++		if (version == 0x15) {
++			memtimings->timing[i].id = i;
++			nv30_mem_timing_entry(dev,&mt_hdr,(struct nouveau_pm_tbl_entry*) &entry[41],0,&memtimings->timing[i]);
++			perflvl->timing = &memtimings->timing[i];
++		} else if (version > 0x15) {
+ 			/* last 3 args are for < 0x40, ignored for >= 0x40 */
+ 			perflvl->timing =
+ 				nouveau_perf_timing(dev, &P,
+diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
+index da8d994..a539fd2 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
++++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
+@@ -64,18 +64,26 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
+ 	if (perflvl == pm->cur)
+ 		return 0;
+ 
+-	if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) {
+-		ret = pm->voltage_set(dev, perflvl->voltage);
++	if (pm->voltage.supported && pm->voltage_set && perflvl->volt_min) {
++		ret = pm->voltage_set(dev, perflvl->volt_min);
+ 		if (ret) {
+ 			NV_ERROR(dev, "voltage_set %d failed: %d\n",
+-				 perflvl->voltage, ret);
++				 perflvl->volt_min, ret);
+ 		}
+ 	}
+ 
+-	nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core);
+-	nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader);
+-	nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory);
+-	nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05);
++	if (pm->clocks_pre) {
++		void *state = pm->clocks_pre(dev, perflvl);
++		if (IS_ERR(state))
++			return PTR_ERR(state);
++		pm->clocks_set(dev, state);
++	} else
++	if (pm->clock_set) {
++		nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core);
++		nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader);
++		nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory);
++		nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05);
++	}
+ 
+ 	pm->cur = perflvl;
+ 	return 0;
+@@ -92,9 +100,6 @@ nouveau_pm_profile_set(struct drm_device *dev, const char *profile)
+ 	if (nouveau_perflvl_wr != 7777)
+ 		return -EPERM;
+ 
+-	if (!pm->clock_set)
+-		return -EINVAL;
+-
+ 	if (!strncmp(profile, "boot", 4))
+ 		perflvl = &pm->boot;
+ 	else {
+@@ -123,31 +128,37 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
+ 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ 	int ret;
+ 
+-	if (!pm->clock_get)
+-		return -EINVAL;
+-
+ 	memset(perflvl, 0, sizeof(*perflvl));
+ 
+-	ret = pm->clock_get(dev, PLL_CORE);
+-	if (ret > 0)
+-		perflvl->core = ret;
++	if (pm->clocks_get) {
++		ret = pm->clocks_get(dev, perflvl);
++		if (ret)
++			return ret;
++	} else
++	if (pm->clock_get) {
++		ret = pm->clock_get(dev, PLL_CORE);
++		if (ret > 0)
++			perflvl->core = ret;
+ 
+-	ret = pm->clock_get(dev, PLL_MEMORY);
+-	if (ret > 0)
+-		perflvl->memory = ret;
++		ret = pm->clock_get(dev, PLL_MEMORY);
++		if (ret > 0)
++			perflvl->memory = ret;
+ 
+-	ret = pm->clock_get(dev, PLL_SHADER);
+-	if (ret > 0)
+-		perflvl->shader = ret;
++		ret = pm->clock_get(dev, PLL_SHADER);
++		if (ret > 0)
++			perflvl->shader = ret;
+ 
+-	ret = pm->clock_get(dev, PLL_UNK05);
+-	if (ret > 0)
+-		perflvl->unk05 = ret;
++		ret = pm->clock_get(dev, PLL_UNK05);
++		if (ret > 0)
++			perflvl->unk05 = ret;
++	}
+ 
+ 	if (pm->voltage.supported && pm->voltage_get) {
+ 		ret = pm->voltage_get(dev);
+-		if (ret > 0)
+-			perflvl->voltage = ret;
++		if (ret > 0) {
++			perflvl->volt_min = ret;
++			perflvl->volt_max = ret;
++		}
+ 	}
+ 
+ 	return 0;
+@@ -156,7 +167,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
+ static void
+ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
+ {
+-	char c[16], s[16], v[16], f[16], t[16];
++	char c[16], s[16], v[32], f[16], t[16], m[16];
+ 
+ 	c[0] = '\0';
+ 	if (perflvl->core)
+@@ -166,9 +177,19 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
+ 	if (perflvl->shader)
+ 		snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000);
+ 
++	m[0] = '\0';
++	if (perflvl->memory)
++		snprintf(m, sizeof(m), " memory %dMHz", perflvl->memory / 1000);
++
+ 	v[0] = '\0';
+-	if (perflvl->voltage)
+-		snprintf(v, sizeof(v), " voltage %dmV", perflvl->voltage * 10);
++	if (perflvl->volt_min && perflvl->volt_min != perflvl->volt_max) {
++		snprintf(v, sizeof(v), " voltage %dmV-%dmV",
++			 perflvl->volt_min / 1000, perflvl->volt_max / 1000);
++	} else
++	if (perflvl->volt_min) {
++		snprintf(v, sizeof(v), " voltage %dmV",
++			 perflvl->volt_min / 1000);
++	}
+ 
+ 	f[0] = '\0';
+ 	if (perflvl->fanspeed)
+@@ -178,8 +199,7 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
+ 	if (perflvl->timing)
+ 		snprintf(t, sizeof(t), " timing %d", perflvl->timing->id);
+ 
+-	snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000,
+-		 c, s, v, f, t);
++	snprintf(ptr, len, "%s%s%s%s%s%s\n", c, s, m, t, v, f);
+ }
+ 
+ static ssize_t
+@@ -190,7 +210,7 @@ nouveau_pm_get_perflvl_info(struct device *d,
+ 	char *ptr = buf;
+ 	int len = PAGE_SIZE;
+ 
+-	snprintf(ptr, len, "%d: ", perflvl->id);
++	snprintf(ptr, len, "%d:", perflvl->id);
+ 	ptr += strlen(buf);
+ 	len -= strlen(buf);
+ 
+@@ -211,9 +231,9 @@ nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf)
+ 	if (!pm->cur)
+ 		snprintf(ptr, len, "setting: boot\n");
+ 	else if (pm->cur == &pm->boot)
+-		snprintf(ptr, len, "setting: boot\nc: ");
++		snprintf(ptr, len, "setting: boot\nc:");
+ 	else
+-		snprintf(ptr, len, "setting: static %d\nc: ", pm->cur->id);
++		snprintf(ptr, len, "setting: static %d\nc:", pm->cur->id);
+ 	ptr += strlen(buf);
+ 	len -= strlen(buf);
+ 
+@@ -292,7 +312,7 @@ nouveau_sysfs_fini(struct drm_device *dev)
+ 	}
+ }
+ 
+-#ifdef CONFIG_HWMON
++#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
+ static ssize_t
+ nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
+ {
+@@ -409,7 +429,7 @@ static const struct attribute_group hwmon_attrgroup = {
+ static int
+ nouveau_hwmon_init(struct drm_device *dev)
+ {
+-#ifdef CONFIG_HWMON
++#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ 	struct device *hwmon_dev;
+@@ -442,7 +462,7 @@ nouveau_hwmon_init(struct drm_device *dev)
+ static void
+ nouveau_hwmon_fini(struct drm_device *dev)
+ {
+-#ifdef CONFIG_HWMON
++#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ 
+@@ -488,7 +508,7 @@ nouveau_pm_init(struct drm_device *dev)
+ 	NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
+ 	for (i = 0; i < pm->nr_perflvl; i++) {
+ 		nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info));
+-		NV_INFO(dev, "%d: %s", pm->perflvl[i].id, info);
++		NV_INFO(dev, "%d:%s", pm->perflvl[i].id, info);
+ 	}
+ 
+ 	/* determine current ("boot") performance level */
+@@ -498,7 +518,7 @@ nouveau_pm_init(struct drm_device *dev)
+ 		pm->cur = &pm->boot;
+ 
+ 		nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
+-		NV_INFO(dev, "c: %s", info);
++		NV_INFO(dev, "c:%s", info);
+ 	}
+ 
+ 	/* switch performance levels now if requested */
+diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
+index 4a9838dd..8ac02cd 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_pm.h
++++ b/drivers/gpu/drm/nouveau/nouveau_pm.h
+@@ -52,6 +52,11 @@ void *nv04_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
+ 			u32 id, int khz);
+ void nv04_pm_clock_set(struct drm_device *, void *);
+ 
++/* nv40_pm.c */
++int nv40_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
++void *nv40_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *);
++void nv40_pm_clocks_set(struct drm_device *, void *);
++
+ /* nv50_pm.c */
+ int nv50_pm_clock_get(struct drm_device *, u32 id);
+ void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
+@@ -59,10 +64,12 @@ void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
+ void nv50_pm_clock_set(struct drm_device *, void *);
+ 
+ /* nva3_pm.c */
+-int nva3_pm_clock_get(struct drm_device *, u32 id);
+-void *nva3_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
+-			u32 id, int khz);
+-void nva3_pm_clock_set(struct drm_device *, void *);
++int nva3_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
++void *nva3_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *);
++void nva3_pm_clocks_set(struct drm_device *, void *);
++
++/* nvc0_pm.c */
++int nvc0_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
+ 
+ /* nouveau_temp.c */
+ void nouveau_temp_init(struct drm_device *dev);
+diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
+index f18cdfc..43a96b9 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
++++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
+@@ -826,9 +826,12 @@
+ #define NV50_PDISPLAY_SOR_DPMS_STATE_ACTIVE                          0x00030000
+ #define NV50_PDISPLAY_SOR_DPMS_STATE_BLANKED                         0x00080000
+ #define NV50_PDISPLAY_SOR_DPMS_STATE_WAIT                            0x10000000
+-#define NV50_PDISPLAY_SOR_BACKLIGHT                                  0x0061c084
+-#define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE                           0x80000000
+-#define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL                            0x00000fff
++#define NV50_PDISP_SOR_PWM_DIV(i)                     (0x0061c080 + (i) * 0x800)
++#define NV50_PDISP_SOR_PWM_CTL(i)                     (0x0061c084 + (i) * 0x800)
++#define NV50_PDISP_SOR_PWM_CTL_NEW                                   0x80000000
++#define NVA3_PDISP_SOR_PWM_CTL_UNK                                   0x40000000
++#define NV50_PDISP_SOR_PWM_CTL_VAL                                   0x000007ff
++#define NVA3_PDISP_SOR_PWM_CTL_VAL                                   0x00ffffff
+ #define NV50_SOR_DP_CTRL(i, l)           (0x0061c10c + (i) * 0x800 + (l) * 0x80)
+ #define NV50_SOR_DP_CTRL_ENABLED                                     0x00000001
+ #define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED                      0x00004000
+@@ -843,7 +846,7 @@
+ #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2                          0x02000000
+ #define NV50_SOR_DP_UNK118(i, l)         (0x0061c118 + (i) * 0x800 + (l) * 0x80)
+ #define NV50_SOR_DP_UNK120(i, l)         (0x0061c120 + (i) * 0x800 + (l) * 0x80)
+-#define NV50_SOR_DP_UNK128(i, l)         (0x0061c128 + (i) * 0x800 + (l) * 0x80)
++#define NV50_SOR_DP_SCFG(i, l)           (0x0061c128 + (i) * 0x800 + (l) * 0x80)
+ #define NV50_SOR_DP_UNK130(i, l)         (0x0061c130 + (i) * 0x800 + (l) * 0x80)
+ 
+ #define NV50_PDISPLAY_USER(i)                        ((i) * 0x1000 + 0x00640000)
+diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+index 2706cb3..b75258a 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
++++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+@@ -12,8 +12,8 @@ struct nouveau_sgdma_be {
+ 	struct drm_device *dev;
+ 
+ 	dma_addr_t *pages;
+-	bool *ttm_alloced;
+ 	unsigned nr_pages;
++	bool unmap_pages;
+ 
+ 	u64 offset;
+ 	bool bound;
+@@ -26,43 +26,28 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages,
+ {
+ 	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
+ 	struct drm_device *dev = nvbe->dev;
++	int i;
+ 
+ 	NV_DEBUG(nvbe->dev, "num_pages = %ld\n", num_pages);
+ 
+-	if (nvbe->pages)
+-		return -EINVAL;
+-
+-	nvbe->pages = kmalloc(sizeof(dma_addr_t) * num_pages, GFP_KERNEL);
+-	if (!nvbe->pages)
+-		return -ENOMEM;
++	nvbe->pages = dma_addrs;
++	nvbe->nr_pages = num_pages;
++	nvbe->unmap_pages = true;
+ 
+-	nvbe->ttm_alloced = kmalloc(sizeof(bool) * num_pages, GFP_KERNEL);
+-	if (!nvbe->ttm_alloced) {
+-		kfree(nvbe->pages);
+-		nvbe->pages = NULL;
+-		return -ENOMEM;
++	/* this code path isn't called and is incorrect anyways */
++	if (0) { /* dma_addrs[0] != DMA_ERROR_CODE) { */
++		nvbe->unmap_pages = false;
++		return 0;
+ 	}
+ 
+-	nvbe->nr_pages = 0;
+-	while (num_pages--) {
+-		/* this code path isn't called and is incorrect anyways */
+-		if (0) { /*dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE)*/
+-			nvbe->pages[nvbe->nr_pages] =
+-					dma_addrs[nvbe->nr_pages];
+-		 	nvbe->ttm_alloced[nvbe->nr_pages] = true;
+-		} else {
+-			nvbe->pages[nvbe->nr_pages] =
+-				pci_map_page(dev->pdev, pages[nvbe->nr_pages], 0,
+-				     PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+-			if (pci_dma_mapping_error(dev->pdev,
+-						  nvbe->pages[nvbe->nr_pages])) {
+-				be->func->clear(be);
+-				return -EFAULT;
+-			}
+-			nvbe->ttm_alloced[nvbe->nr_pages] = false;
++	for (i = 0; i < num_pages; i++) {
++		nvbe->pages[i] = pci_map_page(dev->pdev, pages[i], 0,
++					      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
++		if (pci_dma_mapping_error(dev->pdev, nvbe->pages[i])) {
++			nvbe->nr_pages = --i;
++			be->func->clear(be);
++			return -EFAULT;
+ 		}
+-
+-		nvbe->nr_pages++;
+ 	}
+ 
+ 	return 0;
+@@ -72,25 +57,16 @@ static void
+ nouveau_sgdma_clear(struct ttm_backend *be)
+ {
+ 	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
+-	struct drm_device *dev;
+-
+-	if (nvbe && nvbe->pages) {
+-		dev = nvbe->dev;
+-		NV_DEBUG(dev, "\n");
++	struct drm_device *dev = nvbe->dev;
+ 
+-		if (nvbe->bound)
+-			be->func->unbind(be);
++	if (nvbe->bound)
++		be->func->unbind(be);
+ 
++	if (nvbe->unmap_pages) {
+ 		while (nvbe->nr_pages--) {
+-			if (!nvbe->ttm_alloced[nvbe->nr_pages])
+-				pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages],
++			pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages],
+ 				       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ 		}
+-		kfree(nvbe->pages);
+-		kfree(nvbe->ttm_alloced);
+-		nvbe->pages = NULL;
+-		nvbe->ttm_alloced = NULL;
+-		nvbe->nr_pages = 0;
+ 	}
+ }
+ 
+diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
+index 10656e4..82478e0 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_state.c
++++ b/drivers/gpu/drm/nouveau/nouveau_state.c
+@@ -286,9 +286,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+ 		engine->gpio.get		= nv10_gpio_get;
+ 		engine->gpio.set		= nv10_gpio_set;
+ 		engine->gpio.irq_enable		= NULL;
+-		engine->pm.clock_get		= nv04_pm_clock_get;
+-		engine->pm.clock_pre		= nv04_pm_clock_pre;
+-		engine->pm.clock_set		= nv04_pm_clock_set;
++		engine->pm.clocks_get		= nv40_pm_clocks_get;
++		engine->pm.clocks_pre		= nv40_pm_clocks_pre;
++		engine->pm.clocks_set		= nv40_pm_clocks_set;
+ 		engine->pm.voltage_get		= nouveau_voltage_gpio_get;
+ 		engine->pm.voltage_set		= nouveau_voltage_gpio_set;
+ 		engine->pm.temp_get		= nv40_temp_get;
+@@ -299,7 +299,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+ 	case 0x50:
+ 	case 0x80: /* gotta love NVIDIA's consistency.. */
+ 	case 0x90:
+-	case 0xA0:
++	case 0xa0:
+ 		engine->instmem.init		= nv50_instmem_init;
+ 		engine->instmem.takedown	= nv50_instmem_takedown;
+ 		engine->instmem.suspend		= nv50_instmem_suspend;
+@@ -359,9 +359,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+ 			engine->pm.clock_set	= nv50_pm_clock_set;
+ 			break;
+ 		default:
+-			engine->pm.clock_get	= nva3_pm_clock_get;
+-			engine->pm.clock_pre	= nva3_pm_clock_pre;
+-			engine->pm.clock_set	= nva3_pm_clock_set;
++			engine->pm.clocks_get	= nva3_pm_clocks_get;
++			engine->pm.clocks_pre	= nva3_pm_clocks_pre;
++			engine->pm.clocks_set	= nva3_pm_clocks_set;
+ 			break;
+ 		}
+ 		engine->pm.voltage_get		= nouveau_voltage_gpio_get;
+@@ -376,7 +376,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+ 		engine->vram.put		= nv50_vram_del;
+ 		engine->vram.flags_valid	= nv50_vram_flags_valid;
+ 		break;
+-	case 0xC0:
++	case 0xc0:
+ 		engine->instmem.init		= nvc0_instmem_init;
+ 		engine->instmem.takedown	= nvc0_instmem_takedown;
+ 		engine->instmem.suspend		= nvc0_instmem_suspend;
+@@ -422,12 +422,73 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+ 		engine->vram.put		= nv50_vram_del;
+ 		engine->vram.flags_valid	= nvc0_vram_flags_valid;
+ 		engine->pm.temp_get		= nv84_temp_get;
++		engine->pm.clocks_get		= nvc0_pm_clocks_get;
++		engine->pm.voltage_get		= nouveau_voltage_gpio_get;
++		engine->pm.voltage_set		= nouveau_voltage_gpio_set;
++		break;
++	case 0xd0:
++		engine->instmem.init		= nvc0_instmem_init;
++		engine->instmem.takedown	= nvc0_instmem_takedown;
++		engine->instmem.suspend		= nvc0_instmem_suspend;
++		engine->instmem.resume		= nvc0_instmem_resume;
++		engine->instmem.get		= nv50_instmem_get;
++		engine->instmem.put		= nv50_instmem_put;
++		engine->instmem.map		= nv50_instmem_map;
++		engine->instmem.unmap		= nv50_instmem_unmap;
++		engine->instmem.flush		= nv84_instmem_flush;
++		engine->mc.init			= nv50_mc_init;
++		engine->mc.takedown		= nv50_mc_takedown;
++		engine->timer.init		= nv04_timer_init;
++		engine->timer.read		= nv04_timer_read;
++		engine->timer.takedown		= nv04_timer_takedown;
++		engine->fb.init			= nvc0_fb_init;
++		engine->fb.takedown		= nvc0_fb_takedown;
++		engine->fifo.channels		= 128;
++		engine->fifo.init		= nvc0_fifo_init;
++		engine->fifo.takedown		= nvc0_fifo_takedown;
++		engine->fifo.disable		= nvc0_fifo_disable;
++		engine->fifo.enable		= nvc0_fifo_enable;
++		engine->fifo.reassign		= nvc0_fifo_reassign;
++		engine->fifo.channel_id		= nvc0_fifo_channel_id;
++		engine->fifo.create_context	= nvc0_fifo_create_context;
++		engine->fifo.destroy_context	= nvc0_fifo_destroy_context;
++		engine->fifo.load_context	= nvc0_fifo_load_context;
++		engine->fifo.unload_context	= nvc0_fifo_unload_context;
++		engine->display.early_init	= nouveau_stub_init;
++		engine->display.late_takedown	= nouveau_stub_takedown;
++		engine->display.create		= nvd0_display_create;
++		engine->display.init		= nvd0_display_init;
++		engine->display.destroy		= nvd0_display_destroy;
++		engine->gpio.init		= nv50_gpio_init;
++		engine->gpio.takedown		= nouveau_stub_takedown;
++		engine->gpio.get		= nvd0_gpio_get;
++		engine->gpio.set		= nvd0_gpio_set;
++		engine->gpio.irq_register	= nv50_gpio_irq_register;
++		engine->gpio.irq_unregister	= nv50_gpio_irq_unregister;
++		engine->gpio.irq_enable		= nv50_gpio_irq_enable;
++		engine->vram.init		= nvc0_vram_init;
++		engine->vram.takedown		= nv50_vram_fini;
++		engine->vram.get		= nvc0_vram_new;
++		engine->vram.put		= nv50_vram_del;
++		engine->vram.flags_valid	= nvc0_vram_flags_valid;
++		engine->pm.clocks_get		= nvc0_pm_clocks_get;
++		engine->pm.voltage_get		= nouveau_voltage_gpio_get;
++		engine->pm.voltage_set		= nouveau_voltage_gpio_set;
+ 		break;
+ 	default:
+ 		NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
+ 		return 1;
+ 	}
+ 
++	/* headless mode */
++	if (nouveau_modeset == 2) {
++		engine->display.early_init = nouveau_stub_init;
++		engine->display.late_takedown = nouveau_stub_takedown;
++		engine->display.create = nouveau_stub_init;
++		engine->display.init = nouveau_stub_init;
++		engine->display.destroy = nouveau_stub_takedown;
++	}
++
+ 	return 0;
+ }
+ 
+@@ -449,21 +510,6 @@ nouveau_vga_set_decode(void *priv, bool state)
+ 		return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+ }
+ 
+-static int
+-nouveau_card_init_channel(struct drm_device *dev)
+-{
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	int ret;
+-
+-	ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL,
+-				    NvDmaFB, NvDmaTT);
+-	if (ret)
+-		return ret;
+-
+-	mutex_unlock(&dev_priv->channel->mutex);
+-	return 0;
+-}
+-
+ static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
+ 					 enum vga_switcheroo_state state)
+ {
+@@ -630,8 +676,11 @@ nouveau_card_init(struct drm_device *dev)
+ 			break;
+ 		}
+ 
+-		if (dev_priv->card_type == NV_40)
+-			nv40_mpeg_create(dev);
++		if (dev_priv->card_type == NV_40 ||
++		    dev_priv->chipset == 0x31 ||
++		    dev_priv->chipset == 0x34 ||
++		    dev_priv->chipset == 0x36)
++			nv31_mpeg_create(dev);
+ 		else
+ 		if (dev_priv->card_type == NV_50 &&
+ 		    (dev_priv->chipset < 0x98 || dev_priv->chipset == 0xa0))
+@@ -651,41 +700,69 @@ nouveau_card_init(struct drm_device *dev)
+ 			goto out_engine;
+ 	}
+ 
+-	ret = engine->display.create(dev);
++	ret = nouveau_irq_init(dev);
+ 	if (ret)
+ 		goto out_fifo;
+ 
+-	ret = drm_vblank_init(dev, nv_two_heads(dev) ? 2 : 1);
+-	if (ret)
+-		goto out_vblank;
++	/* initialise general modesetting */
++	drm_mode_config_init(dev);
++	drm_mode_create_scaling_mode_property(dev);
++	drm_mode_create_dithering_property(dev);
++	dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs;
++	dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1);
++	dev->mode_config.min_width = 0;
++	dev->mode_config.min_height = 0;
++	if (dev_priv->card_type < NV_10) {
++		dev->mode_config.max_width = 2048;
++		dev->mode_config.max_height = 2048;
++	} else
++	if (dev_priv->card_type < NV_50) {
++		dev->mode_config.max_width = 4096;
++		dev->mode_config.max_height = 4096;
++	} else {
++		dev->mode_config.max_width = 8192;
++		dev->mode_config.max_height = 8192;
++	}
+ 
+-	ret = nouveau_irq_init(dev);
++	ret = engine->display.create(dev);
+ 	if (ret)
+-		goto out_vblank;
++		goto out_irq;
+ 
+-	/* what about PVIDEO/PCRTC/PRAMDAC etc? */
++	nouveau_backlight_init(dev);
+ 
+ 	if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
+ 		ret = nouveau_fence_init(dev);
+ 		if (ret)
+-			goto out_irq;
++			goto out_disp;
+ 
+-		ret = nouveau_card_init_channel(dev);
++		ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL,
++					    NvDmaFB, NvDmaTT);
+ 		if (ret)
+ 			goto out_fence;
++
++		mutex_unlock(&dev_priv->channel->mutex);
++	}
++
++	if (dev->mode_config.num_crtc) {
++		ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
++		if (ret)
++			goto out_chan;
++
++		nouveau_fbcon_init(dev);
++		drm_kms_helper_poll_init(dev);
+ 	}
+ 
+-	nouveau_fbcon_init(dev);
+-	drm_kms_helper_poll_init(dev);
+ 	return 0;
+ 
++out_chan:
++	nouveau_channel_put_unlocked(&dev_priv->channel);
+ out_fence:
+ 	nouveau_fence_fini(dev);
++out_disp:
++	nouveau_backlight_exit(dev);
++	engine->display.destroy(dev);
+ out_irq:
+ 	nouveau_irq_fini(dev);
+-out_vblank:
+-	drm_vblank_cleanup(dev);
+-	engine->display.destroy(dev);
+ out_fifo:
+ 	if (!dev_priv->noaccel)
+ 		engine->fifo.takedown(dev);
+@@ -732,15 +809,20 @@ static void nouveau_card_takedown(struct drm_device *dev)
+ 	struct nouveau_engine *engine = &dev_priv->engine;
+ 	int e;
+ 
+-	drm_kms_helper_poll_fini(dev);
+-	nouveau_fbcon_fini(dev);
++	if (dev->mode_config.num_crtc) {
++		drm_kms_helper_poll_fini(dev);
++		nouveau_fbcon_fini(dev);
++		drm_vblank_cleanup(dev);
++	}
+ 
+ 	if (dev_priv->channel) {
+ 		nouveau_channel_put_unlocked(&dev_priv->channel);
+ 		nouveau_fence_fini(dev);
+ 	}
+ 
++	nouveau_backlight_exit(dev);
+ 	engine->display.destroy(dev);
++	drm_mode_config_cleanup(dev);
+ 
+ 	if (!dev_priv->noaccel) {
+ 		engine->fifo.takedown(dev);
+@@ -774,7 +856,6 @@ static void nouveau_card_takedown(struct drm_device *dev)
+ 	engine->vram.takedown(dev);
+ 
+ 	nouveau_irq_fini(dev);
+-	drm_vblank_cleanup(dev);
+ 
+ 	nouveau_pm_fini(dev);
+ 	nouveau_bios_takedown(dev);
+@@ -907,7 +988,7 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev)
+ int nouveau_load(struct drm_device *dev, unsigned long flags)
+ {
+ 	struct drm_nouveau_private *dev_priv;
+-	uint32_t reg0;
++	uint32_t reg0, strap;
+ 	resource_size_t mmio_start_offs;
+ 	int ret;
+ 
+@@ -951,13 +1032,11 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
+ 
+ 	/* Time to determine the card architecture */
+ 	reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
+-	dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */
+ 
+ 	/* We're dealing with >=NV10 */
+ 	if ((reg0 & 0x0f000000) > 0) {
+ 		/* Bit 27-20 contain the architecture in hex */
+ 		dev_priv->chipset = (reg0 & 0xff00000) >> 20;
+-		dev_priv->stepping = (reg0 & 0xff);
+ 	/* NV04 or NV05 */
+ 	} else if ((reg0 & 0xff00fff0) == 0x20004000) {
+ 		if (reg0 & 0x00f00000)
+@@ -987,6 +1066,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
+ 	case 0xc0:
+ 		dev_priv->card_type = NV_C0;
+ 		break;
++	case 0xd0:
++		dev_priv->card_type = NV_D0;
++		break;
+ 	default:
+ 		NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0);
+ 		ret = -EINVAL;
+@@ -996,6 +1078,23 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
+ 	NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
+ 		dev_priv->card_type, reg0);
+ 
++	/* determine frequency of timing crystal */
++	strap = nv_rd32(dev, 0x101000);
++	if ( dev_priv->chipset < 0x17 ||
++	    (dev_priv->chipset >= 0x20 && dev_priv->chipset <= 0x25))
++		strap &= 0x00000040;
++	else
++		strap &= 0x00400040;
++
++	switch (strap) {
++	case 0x00000000: dev_priv->crystal = 13500; break;
++	case 0x00000040: dev_priv->crystal = 14318; break;
++	case 0x00400000: dev_priv->crystal = 27000; break;
++	case 0x00400040: dev_priv->crystal = 25000; break;
++	}
++
++	NV_DEBUG(dev, "crystal freq: %dKHz\n", dev_priv->crystal);
++
+ 	/* Determine whether we'll attempt acceleration or not, some
+ 	 * cards are disabled by default here due to them being known
+ 	 * non-functional, or never been tested due to lack of hw.
+@@ -1030,7 +1129,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
+ 			ioremap(pci_resource_start(dev->pdev, ramin_bar),
+ 				dev_priv->ramin_size);
+ 		if (!dev_priv->ramin) {
+-			NV_ERROR(dev, "Failed to PRAMIN BAR");
++			NV_ERROR(dev, "Failed to map PRAMIN BAR\n");
+ 			ret = -ENOMEM;
+ 			goto err_mmio;
+ 		}
+@@ -1130,7 +1229,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
+ 		getparam->value = 1;
+ 		break;
+ 	case NOUVEAU_GETPARAM_HAS_PAGEFLIP:
+-		getparam->value = 1;
++		getparam->value = dev_priv->card_type < NV_D0;
+ 		break;
+ 	case NOUVEAU_GETPARAM_GRAPH_UNITS:
+ 		/* NV40 and NV50 versions are quite different, but register
+@@ -1198,6 +1297,23 @@ nouveau_wait_ne(struct drm_device *dev, uint64_t timeout,
+ 	return false;
+ }
+ 
++/* Wait until cond(data) == true, up until timeout has hit */
++bool
++nouveau_wait_cb(struct drm_device *dev, u64 timeout,
++		bool (*cond)(void *), void *data)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
++	u64 start = ptimer->read(dev);
++
++	do {
++		if (cond(data) == true)
++			return true;
++	} while (ptimer->read(dev) - start < timeout);
++
++	return false;
++}
++
+ /* Waits for PGRAPH to go completely idle */
+ bool nouveau_wait_for_idle(struct drm_device *dev)
+ {
+diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.c b/drivers/gpu/drm/nouveau/nouveau_vm.c
+index 244fd38..ef0832b 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_vm.c
++++ b/drivers/gpu/drm/nouveau/nouveau_vm.c
+@@ -172,9 +172,9 @@ nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde)
+ 			vm->map_pgt(vpgd->obj, pde, vpgt->obj);
+ 		}
+ 
+-		mutex_unlock(&vm->mm->mutex);
++		mutex_unlock(&vm->mm.mutex);
+ 		nouveau_gpuobj_ref(NULL, &pgt);
+-		mutex_lock(&vm->mm->mutex);
++		mutex_lock(&vm->mm.mutex);
+ 	}
+ }
+ 
+@@ -191,18 +191,18 @@ nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type)
+ 	pgt_size  = (1 << (vm->pgt_bits + 12)) >> type;
+ 	pgt_size *= 8;
+ 
+-	mutex_unlock(&vm->mm->mutex);
++	mutex_unlock(&vm->mm.mutex);
+ 	ret = nouveau_gpuobj_new(vm->dev, NULL, pgt_size, 0x1000,
+ 				 NVOBJ_FLAG_ZERO_ALLOC, &pgt);
+-	mutex_lock(&vm->mm->mutex);
++	mutex_lock(&vm->mm.mutex);
+ 	if (unlikely(ret))
+ 		return ret;
+ 
+ 	/* someone beat us to filling the PDE while we didn't have the lock */
+ 	if (unlikely(vpgt->refcount[big]++)) {
+-		mutex_unlock(&vm->mm->mutex);
++		mutex_unlock(&vm->mm.mutex);
+ 		nouveau_gpuobj_ref(NULL, &pgt);
+-		mutex_lock(&vm->mm->mutex);
++		mutex_lock(&vm->mm.mutex);
+ 		return 0;
+ 	}
+ 
+@@ -223,10 +223,10 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift,
+ 	u32 fpde, lpde, pde;
+ 	int ret;
+ 
+-	mutex_lock(&vm->mm->mutex);
+-	ret = nouveau_mm_get(vm->mm, page_shift, msize, 0, align, &vma->node);
++	mutex_lock(&vm->mm.mutex);
++	ret = nouveau_mm_get(&vm->mm, page_shift, msize, 0, align, &vma->node);
+ 	if (unlikely(ret != 0)) {
+-		mutex_unlock(&vm->mm->mutex);
++		mutex_unlock(&vm->mm.mutex);
+ 		return ret;
+ 	}
+ 
+@@ -245,13 +245,13 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift,
+ 		if (ret) {
+ 			if (pde != fpde)
+ 				nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1);
+-			nouveau_mm_put(vm->mm, vma->node);
+-			mutex_unlock(&vm->mm->mutex);
++			nouveau_mm_put(&vm->mm, vma->node);
++			mutex_unlock(&vm->mm.mutex);
+ 			vma->node = NULL;
+ 			return ret;
+ 		}
+ 	}
+-	mutex_unlock(&vm->mm->mutex);
++	mutex_unlock(&vm->mm.mutex);
+ 
+ 	vma->vm     = vm;
+ 	vma->offset = (u64)vma->node->offset << 12;
+@@ -270,11 +270,11 @@ nouveau_vm_put(struct nouveau_vma *vma)
+ 	fpde = (vma->node->offset >> vm->pgt_bits);
+ 	lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits;
+ 
+-	mutex_lock(&vm->mm->mutex);
++	mutex_lock(&vm->mm.mutex);
+ 	nouveau_vm_unmap_pgt(vm, vma->node->type != vm->spg_shift, fpde, lpde);
+-	nouveau_mm_put(vm->mm, vma->node);
++	nouveau_mm_put(&vm->mm, vma->node);
+ 	vma->node = NULL;
+-	mutex_unlock(&vm->mm->mutex);
++	mutex_unlock(&vm->mm.mutex);
+ }
+ 
+ int
+@@ -306,7 +306,7 @@ nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset,
+ 			block = length;
+ 
+ 	} else
+-	if (dev_priv->card_type == NV_C0) {
++	if (dev_priv->card_type >= NV_C0) {
+ 		vm->map_pgt = nvc0_vm_map_pgt;
+ 		vm->map = nvc0_vm_map;
+ 		vm->map_sg = nvc0_vm_map_sg;
+@@ -360,11 +360,11 @@ nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd)
+ 
+ 	nouveau_gpuobj_ref(pgd, &vpgd->obj);
+ 
+-	mutex_lock(&vm->mm->mutex);
++	mutex_lock(&vm->mm.mutex);
+ 	for (i = vm->fpde; i <= vm->lpde; i++)
+ 		vm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj);
+ 	list_add(&vpgd->head, &vm->pgd_list);
+-	mutex_unlock(&vm->mm->mutex);
++	mutex_unlock(&vm->mm.mutex);
+ 	return 0;
+ }
+ 
+@@ -377,7 +377,7 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
+ 	if (!mpgd)
+ 		return;
+ 
+-	mutex_lock(&vm->mm->mutex);
++	mutex_lock(&vm->mm.mutex);
+ 	list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
+ 		if (vpgd->obj == mpgd) {
+ 			pgd = vpgd->obj;
+@@ -386,7 +386,7 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
+ 			break;
+ 		}
+ 	}
+-	mutex_unlock(&vm->mm->mutex);
++	mutex_unlock(&vm->mm.mutex);
+ 
+ 	nouveau_gpuobj_ref(NULL, &pgd);
+ }
+diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.h b/drivers/gpu/drm/nouveau/nouveau_vm.h
+index 579ca8c..6ce995f 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_vm.h
++++ b/drivers/gpu/drm/nouveau/nouveau_vm.h
+@@ -51,7 +51,7 @@ struct nouveau_vma {
+ 
+ struct nouveau_vm {
+ 	struct drm_device *dev;
+-	struct nouveau_mm *mm;
++	struct nouveau_mm mm;
+ 	int refcount;
+ 
+ 	struct list_head pgd_list;
+diff --git a/drivers/gpu/drm/nouveau/nouveau_volt.c b/drivers/gpu/drm/nouveau/nouveau_volt.c
+index 75e87274..86d03e1 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_volt.c
++++ b/drivers/gpu/drm/nouveau/nouveau_volt.c
+@@ -27,7 +27,7 @@
+ #include "nouveau_drv.h"
+ #include "nouveau_pm.h"
+ 
+-static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a };
++static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 };
+ static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]);
+ 
+ int
+@@ -170,6 +170,13 @@ nouveau_volt_init(struct drm_device *dev)
+ 		 */
+ 		vidshift  = 2;
+ 		break;
++	case 0x40:
++		headerlen = volt[1];
++		recordlen = volt[2];
++		entries   = volt[3]; /* not a clue what the entries are for.. */
++		vidmask   = volt[11]; /* guess.. */
++		vidshift  = 0;
++		break;
+ 	default:
+ 		NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]);
+ 		return;
+@@ -197,16 +204,37 @@ nouveau_volt_init(struct drm_device *dev)
+ 	}
+ 
+ 	/* parse vbios entries into common format */
+-	voltage->level = kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL);
+-	if (!voltage->level)
+-		return;
++	voltage->version = volt[0];
++	if (voltage->version < 0x40) {
++		voltage->nr_level = entries;
++		voltage->level =
++			kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL);
++		if (!voltage->level)
++			return;
+ 
+-	entry = volt + headerlen;
+-	for (i = 0; i < entries; i++, entry += recordlen) {
+-		voltage->level[i].voltage = entry[0];
+-		voltage->level[i].vid     = entry[1] >> vidshift;
++		entry = volt + headerlen;
++		for (i = 0; i < entries; i++, entry += recordlen) {
++			voltage->level[i].voltage = entry[0] * 10000;
++			voltage->level[i].vid     = entry[1] >> vidshift;
++		}
++	} else {
++		u32 volt_uv = ROM32(volt[4]);
++		s16 step_uv = ROM16(volt[8]);
++		u8 vid;
++
++		voltage->nr_level = voltage->vid_mask + 1;
++		voltage->level = kcalloc(voltage->nr_level,
++					 sizeof(*voltage->level), GFP_KERNEL);
++		if (!voltage->level)
++			return;
++
++		for (vid = 0; vid <= voltage->vid_mask; vid++) {
++			voltage->level[vid].voltage = volt_uv;
++			voltage->level[vid].vid = vid;
++			volt_uv += step_uv;
++		}
+ 	}
+-	voltage->nr_level  = entries;
++
+ 	voltage->supported = true;
+ }
+ 
+diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c
+index 1715e14..6bd8518 100644
+--- a/drivers/gpu/drm/nouveau/nv04_display.c
++++ b/drivers/gpu/drm/nouveau/nv04_display.c
+@@ -126,27 +126,6 @@ nv04_display_create(struct drm_device *dev)
+ 
+ 	nouveau_hw_save_vga_fonts(dev, 1);
+ 
+-	drm_mode_config_init(dev);
+-	drm_mode_create_scaling_mode_property(dev);
+-	drm_mode_create_dithering_property(dev);
+-
+-	dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs;
+-
+-	dev->mode_config.min_width = 0;
+-	dev->mode_config.min_height = 0;
+-	switch (dev_priv->card_type) {
+-	case NV_04:
+-		dev->mode_config.max_width = 2048;
+-		dev->mode_config.max_height = 2048;
+-		break;
+-	default:
+-		dev->mode_config.max_width = 4096;
+-		dev->mode_config.max_height = 4096;
+-		break;
+-	}
+-
+-	dev->mode_config.fb_base = dev_priv->fb_phys;
+-
+ 	nv04_crtc_create(dev, 0);
+ 	if (nv_two_heads(dev))
+ 		nv04_crtc_create(dev, 1);
+@@ -235,8 +214,6 @@ nv04_display_destroy(struct drm_device *dev)
+ 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+ 		crtc->funcs->restore(crtc);
+ 
+-	drm_mode_config_cleanup(dev);
+-
+ 	nouveau_hw_save_vga_fonts(dev, 0);
+ }
+ 
+diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c
+index eb1c70d..9ae92a8 100644
+--- a/drivers/gpu/drm/nouveau/nv04_pm.c
++++ b/drivers/gpu/drm/nouveau/nv04_pm.c
+@@ -68,6 +68,7 @@ void
+ nv04_pm_clock_set(struct drm_device *dev, void *pre_state)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+ 	struct nv04_pm_state *state = pre_state;
+ 	u32 reg = state->pll.reg;
+ 
+@@ -85,6 +86,9 @@ nv04_pm_clock_set(struct drm_device *dev, void *pre_state)
+ 		nv_mask(dev, 0x1002c0, 0, 1 << 8);
+ 	}
+ 
++	if (reg == NV_PRAMDAC_NVPLL_COEFF)
++		ptimer->init(dev);
++
+ 	kfree(state);
+ }
+ 
+diff --git a/drivers/gpu/drm/nouveau/nv04_timer.c b/drivers/gpu/drm/nouveau/nv04_timer.c
+index 1d09ddd..263301b 100644
+--- a/drivers/gpu/drm/nouveau/nv04_timer.c
++++ b/drivers/gpu/drm/nouveau/nv04_timer.c
+@@ -6,43 +6,75 @@
+ int
+ nv04_timer_init(struct drm_device *dev)
+ {
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	u32 m, n, d;
++
+ 	nv_wr32(dev, NV04_PTIMER_INTR_EN_0, 0x00000000);
+ 	nv_wr32(dev, NV04_PTIMER_INTR_0, 0xFFFFFFFF);
+ 
+-	/* Just use the pre-existing values when possible for now; these regs
+-	 * are not written in nv (driver writer missed a /4 on the address), and
+-	 * writing 8 and 3 to the correct regs breaks the timings on the LVDS
+-	 * hardware sequencing microcode.
+-	 * A correct solution (involving calculations with the GPU PLL) can
+-	 * be done when kernel modesetting lands
+-	 */
+-	if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) ||
+-				!nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) {
+-		nv_wr32(dev, NV04_PTIMER_NUMERATOR, 0x00000008);
+-		nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 0x00000003);
++	/* aim for 31.25MHz, which gives us nanosecond timestamps */
++	d = 1000000 / 32;
++
++	/* determine base clock for timer source */
++	if (dev_priv->chipset < 0x40) {
++		n = dev_priv->engine.pm.clock_get(dev, PLL_CORE);
++	} else
++	if (dev_priv->chipset == 0x40) {
++		/*XXX: figure this out */
++		n = 0;
++	} else {
++		n = dev_priv->crystal;
++		m = 1;
++		while (n < (d * 2)) {
++			n += (n / m);
++			m++;
++		}
++
++		nv_wr32(dev, 0x009220, m - 1);
++	}
++
++	if (!n) {
++		NV_WARN(dev, "PTIMER: unknown input clock freq\n");
++		if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) ||
++		    !nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) {
++			nv_wr32(dev, NV04_PTIMER_NUMERATOR, 1);
++			nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 1);
++		}
++		return 0;
++	}
++
++	/* reduce ratio to acceptable values */
++	while (((n % 5) == 0) && ((d % 5) == 0)) {
++		n /= 5;
++		d /= 5;
+ 	}
+ 
++	while (((n % 2) == 0) && ((d % 2) == 0)) {
++		n /= 2;
++		d /= 2;
++	}
++
++	while (n > 0xffff || d > 0xffff) {
++		n >>= 1;
++		d >>= 1;
++	}
++
++	nv_wr32(dev, NV04_PTIMER_NUMERATOR, n);
++	nv_wr32(dev, NV04_PTIMER_DENOMINATOR, d);
+ 	return 0;
+ }
+ 
+-uint64_t
++u64
+ nv04_timer_read(struct drm_device *dev)
+ {
+-	uint32_t low;
+-	/* From kmmio dumps on nv28 this looks like how the blob does this.
+-	 * It reads the high dword twice, before and after.
+-	 * The only explanation seems to be that the 64-bit timer counter
+-	 * advances between high and low dword reads and may corrupt the
+-	 * result. Not confirmed.
+-	 */
+-	uint32_t high2 = nv_rd32(dev, NV04_PTIMER_TIME_1);
+-	uint32_t high1;
++	u32 hi, lo;
++
+ 	do {
+-		high1 = high2;
+-		low = nv_rd32(dev, NV04_PTIMER_TIME_0);
+-		high2 = nv_rd32(dev, NV04_PTIMER_TIME_1);
+-	} while (high1 != high2);
+-	return (((uint64_t)high2) << 32) | (uint64_t)low;
++		hi = nv_rd32(dev, NV04_PTIMER_TIME_1);
++		lo = nv_rd32(dev, NV04_PTIMER_TIME_0);
++	} while (hi != nv_rd32(dev, NV04_PTIMER_TIME_1));
++
++	return ((u64)hi << 32 | lo);
+ }
+ 
+ void
+diff --git a/drivers/gpu/drm/nouveau/nv31_mpeg.c b/drivers/gpu/drm/nouveau/nv31_mpeg.c
+new file mode 100644
+index 0000000..6f06a07
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nv31_mpeg.c
+@@ -0,0 +1,344 @@
++/*
++ * Copyright 2011 Red Hat Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: Ben Skeggs
++ */
++
++#include "drmP.h"
++#include "nouveau_drv.h"
++#include "nouveau_ramht.h"
++
++struct nv31_mpeg_engine {
++	struct nouveau_exec_engine base;
++	atomic_t refcount;
++};
++
++
++static int
++nv31_mpeg_context_new(struct nouveau_channel *chan, int engine)
++{
++	struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine);
++
++	if (!atomic_add_unless(&pmpeg->refcount, 1, 1))
++		return -EBUSY;
++
++	chan->engctx[engine] = (void *)0xdeadcafe;
++	return 0;
++}
++
++static void
++nv31_mpeg_context_del(struct nouveau_channel *chan, int engine)
++{
++	struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine);
++	atomic_dec(&pmpeg->refcount);
++	chan->engctx[engine] = NULL;
++}
++
++static int
++nv40_mpeg_context_new(struct nouveau_channel *chan, int engine)
++{
++	struct drm_device *dev = chan->dev;
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nouveau_gpuobj *ctx = NULL;
++	unsigned long flags;
++	int ret;
++
++	NV_DEBUG(dev, "ch%d\n", chan->id);
++
++	ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC |
++				 NVOBJ_FLAG_ZERO_FREE, &ctx);
++	if (ret)
++		return ret;
++
++	nv_wo32(ctx, 0x78, 0x02001ec1);
++
++	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
++	nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
++	if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id)
++		nv_wr32(dev, 0x00330c, ctx->pinst >> 4);
++	nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4);
++	nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
++	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
++
++	chan->engctx[engine] = ctx;
++	return 0;
++}
++
++static void
++nv40_mpeg_context_del(struct nouveau_channel *chan, int engine)
++{
++	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
++	struct nouveau_gpuobj *ctx = chan->engctx[engine];
++	struct drm_device *dev = chan->dev;
++	unsigned long flags;
++	u32 inst = 0x80000000 | (ctx->pinst >> 4);
++
++	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
++	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
++	if (nv_rd32(dev, 0x00b318) == inst)
++		nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
++	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
++	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
++
++	nouveau_gpuobj_ref(NULL, &ctx);
++	chan->engctx[engine] = NULL;
++}
++
++static int
++nv31_mpeg_object_new(struct nouveau_channel *chan, int engine,
++		      u32 handle, u16 class)
++{
++	struct drm_device *dev = chan->dev;
++	struct nouveau_gpuobj *obj = NULL;
++	int ret;
++
++	ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC |
++				 NVOBJ_FLAG_ZERO_FREE, &obj);
++	if (ret)
++		return ret;
++	obj->engine = 2;
++	obj->class  = class;
++
++	nv_wo32(obj, 0x00, class);
++
++	ret = nouveau_ramht_insert(chan, handle, obj);
++	nouveau_gpuobj_ref(NULL, &obj);
++	return ret;
++}
++
++static int
++nv31_mpeg_init(struct drm_device *dev, int engine)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine);
++	int i;
++
++	/* VPE init */
++	nv_mask(dev, 0x000200, 0x00000002, 0x00000000);
++	nv_mask(dev, 0x000200, 0x00000002, 0x00000002);
++	nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
++	nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
++
++	for (i = 0; i < dev_priv->engine.fb.num_tiles; i++)
++		pmpeg->base.set_tile_region(dev, i);
++
++	/* PMPEG init */
++	nv_wr32(dev, 0x00b32c, 0x00000000);
++	nv_wr32(dev, 0x00b314, 0x00000100);
++	nv_wr32(dev, 0x00b220, nv44_graph_class(dev) ? 0x00000044 : 0x00000031);
++	nv_wr32(dev, 0x00b300, 0x02001ec1);
++	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
++
++	nv_wr32(dev, 0x00b100, 0xffffffff);
++	nv_wr32(dev, 0x00b140, 0xffffffff);
++
++	if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
++		NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
++		return -EBUSY;
++	}
++
++	return 0;
++}
++
++static int
++nv31_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
++{
++	/*XXX: context save? */
++	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
++	nv_wr32(dev, 0x00b140, 0x00000000);
++	return 0;
++}
++
++static int
++nv31_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
++{
++	struct drm_device *dev = chan->dev;
++	u32 inst = data << 4;
++	u32 dma0 = nv_ri32(dev, inst + 0);
++	u32 dma1 = nv_ri32(dev, inst + 4);
++	u32 dma2 = nv_ri32(dev, inst + 8);
++	u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
++	u32 size = dma1 + 1;
++
++	/* only allow linear DMA objects */
++	if (!(dma0 & 0x00002000))
++		return -EINVAL;
++
++	if (mthd == 0x0190) {
++		/* DMA_CMD */
++		nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000));
++		nv_wr32(dev, 0x00b334, base);
++		nv_wr32(dev, 0x00b324, size);
++	} else
++	if (mthd == 0x01a0) {
++		/* DMA_DATA */
++		nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
++		nv_wr32(dev, 0x00b360, base);
++		nv_wr32(dev, 0x00b364, size);
++	} else {
++		/* DMA_IMAGE, VRAM only */
++		if (dma0 & 0x000c0000)
++			return -EINVAL;
++
++		nv_wr32(dev, 0x00b370, base);
++		nv_wr32(dev, 0x00b374, size);
++	}
++
++	return 0;
++}
++
++static int
++nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nouveau_gpuobj *ctx;
++	unsigned long flags;
++	int i;
++
++	/* hardcode drm channel id on nv3x, so swmthd lookup works */
++	if (dev_priv->card_type < NV_40)
++		return 0;
++
++	spin_lock_irqsave(&dev_priv->channels.lock, flags);
++	for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
++		if (!dev_priv->channels.ptr[i])
++			continue;
++
++		ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG];
++		if (ctx && ctx->pinst == inst)
++			break;
++	}
++	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
++	return i;
++}
++
++static void
++nv31_vpe_set_tile_region(struct drm_device *dev, int i)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
++
++	nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch);
++	nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit);
++	nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr);
++}
++
++static void
++nv31_mpeg_isr(struct drm_device *dev)
++{
++	u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4;
++	u32 chid = nv31_mpeg_isr_chid(dev, inst);
++	u32 stat = nv_rd32(dev, 0x00b100);
++	u32 type = nv_rd32(dev, 0x00b230);
++	u32 mthd = nv_rd32(dev, 0x00b234);
++	u32 data = nv_rd32(dev, 0x00b238);
++	u32 show = stat;
++
++	if (stat & 0x01000000) {
++		/* happens on initial binding of the object */
++		if (type == 0x00000020 && mthd == 0x0000) {
++			nv_mask(dev, 0x00b308, 0x00000000, 0x00000000);
++			show &= ~0x01000000;
++		}
++
++		if (type == 0x00000010) {
++			if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data))
++				show &= ~0x01000000;
++		}
++	}
++
++	nv_wr32(dev, 0x00b100, stat);
++	nv_wr32(dev, 0x00b230, 0x00000001);
++
++	if (show && nouveau_ratelimit()) {
++		NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
++			chid, inst, stat, type, mthd, data);
++	}
++}
++
++static void
++nv31_vpe_isr(struct drm_device *dev)
++{
++	if (nv_rd32(dev, 0x00b100))
++		nv31_mpeg_isr(dev);
++
++	if (nv_rd32(dev, 0x00b800)) {
++		u32 stat = nv_rd32(dev, 0x00b800);
++		NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
++		nv_wr32(dev, 0xb800, stat);
++	}
++}
++
++static void
++nv31_mpeg_destroy(struct drm_device *dev, int engine)
++{
++	struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine);
++
++	nouveau_irq_unregister(dev, 0);
++
++	NVOBJ_ENGINE_DEL(dev, MPEG);
++	kfree(pmpeg);
++}
++
++int
++nv31_mpeg_create(struct drm_device *dev)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nv31_mpeg_engine *pmpeg;
++
++	pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
++	if (!pmpeg)
++		return -ENOMEM;
++	atomic_set(&pmpeg->refcount, 0);
++
++	pmpeg->base.destroy = nv31_mpeg_destroy;
++	pmpeg->base.init = nv31_mpeg_init;
++	pmpeg->base.fini = nv31_mpeg_fini;
++	if (dev_priv->card_type < NV_40) {
++		pmpeg->base.context_new = nv31_mpeg_context_new;
++		pmpeg->base.context_del = nv31_mpeg_context_del;
++	} else {
++		pmpeg->base.context_new = nv40_mpeg_context_new;
++		pmpeg->base.context_del = nv40_mpeg_context_del;
++	}
++	pmpeg->base.object_new = nv31_mpeg_object_new;
++
++	/* ISR vector, PMC_ENABLE bit,  and TILE regs are shared between
++	 * all VPE engines, for this driver's purposes the PMPEG engine
++	 * will be treated as the "master" and handle the global VPE
++	 * bits too
++	 */
++	pmpeg->base.set_tile_region = nv31_vpe_set_tile_region;
++	nouveau_irq_register(dev, 0, nv31_vpe_isr);
++
++	NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
++	NVOBJ_CLASS(dev, 0x3174, MPEG);
++	NVOBJ_MTHD (dev, 0x3174, 0x0190, nv31_mpeg_mthd_dma);
++	NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv31_mpeg_mthd_dma);
++	NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv31_mpeg_mthd_dma);
++
++#if 0
++	NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
++	NVOBJ_CLASS(dev, 0x4075, ME);
++#endif
++	return 0;
++
++}
+diff --git a/drivers/gpu/drm/nouveau/nv40_mpeg.c b/drivers/gpu/drm/nouveau/nv40_mpeg.c
+deleted file mode 100644
+index ad03a0e..0000000
+--- a/drivers/gpu/drm/nouveau/nv40_mpeg.c
++++ /dev/null
+@@ -1,311 +0,0 @@
+-/*
+- * Copyright 2011 Red Hat Inc.
+- *
+- * Permission is hereby granted, free of charge, to any person obtaining a
+- * copy of this software and associated documentation files (the "Software"),
+- * to deal in the Software without restriction, including without limitation
+- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+- * and/or sell copies of the Software, and to permit persons to whom the
+- * Software is furnished to do so, subject to the following conditions:
+- *
+- * The above copyright notice and this permission notice shall be included in
+- * all copies or substantial portions of the Software.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+- * OTHER DEALINGS IN THE SOFTWARE.
+- *
+- * Authors: Ben Skeggs
+- */
+-
+-#include "drmP.h"
+-#include "nouveau_drv.h"
+-#include "nouveau_ramht.h"
+-
+-struct nv40_mpeg_engine {
+-	struct nouveau_exec_engine base;
+-};
+-
+-static int
+-nv40_mpeg_context_new(struct nouveau_channel *chan, int engine)
+-{
+-	struct drm_device *dev = chan->dev;
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_gpuobj *ctx = NULL;
+-	unsigned long flags;
+-	int ret;
+-
+-	NV_DEBUG(dev, "ch%d\n", chan->id);
+-
+-	ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC |
+-				 NVOBJ_FLAG_ZERO_FREE, &ctx);
+-	if (ret)
+-		return ret;
+-
+-	nv_wo32(ctx, 0x78, 0x02001ec1);
+-
+-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+-	nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
+-	if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id)
+-		nv_wr32(dev, 0x00330c, ctx->pinst >> 4);
+-	nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4);
+-	nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
+-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+-
+-	chan->engctx[engine] = ctx;
+-	return 0;
+-}
+-
+-static void
+-nv40_mpeg_context_del(struct nouveau_channel *chan, int engine)
+-{
+-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+-	struct nouveau_gpuobj *ctx = chan->engctx[engine];
+-	struct drm_device *dev = chan->dev;
+-	unsigned long flags;
+-	u32 inst = 0x80000000 | (ctx->pinst >> 4);
+-
+-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+-	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+-	if (nv_rd32(dev, 0x00b318) == inst)
+-		nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
+-	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+-
+-	nouveau_gpuobj_ref(NULL, &ctx);
+-	chan->engctx[engine] = NULL;
+-}
+-
+-static int
+-nv40_mpeg_object_new(struct nouveau_channel *chan, int engine,
+-		      u32 handle, u16 class)
+-{
+-	struct drm_device *dev = chan->dev;
+-	struct nouveau_gpuobj *obj = NULL;
+-	int ret;
+-
+-	ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC |
+-				 NVOBJ_FLAG_ZERO_FREE, &obj);
+-	if (ret)
+-		return ret;
+-	obj->engine = 2;
+-	obj->class  = class;
+-
+-	nv_wo32(obj, 0x00, class);
+-
+-	ret = nouveau_ramht_insert(chan, handle, obj);
+-	nouveau_gpuobj_ref(NULL, &obj);
+-	return ret;
+-}
+-
+-static int
+-nv40_mpeg_init(struct drm_device *dev, int engine)
+-{
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine);
+-	int i;
+-
+-	/* VPE init */
+-	nv_mask(dev, 0x000200, 0x00000002, 0x00000000);
+-	nv_mask(dev, 0x000200, 0x00000002, 0x00000002);
+-	nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+-	nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+-
+-	for (i = 0; i < dev_priv->engine.fb.num_tiles; i++)
+-		pmpeg->base.set_tile_region(dev, i);
+-
+-	/* PMPEG init */
+-	nv_wr32(dev, 0x00b32c, 0x00000000);
+-	nv_wr32(dev, 0x00b314, 0x00000100);
+-	nv_wr32(dev, 0x00b220, 0x00000044);
+-	nv_wr32(dev, 0x00b300, 0x02001ec1);
+-	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+-
+-	nv_wr32(dev, 0x00b100, 0xffffffff);
+-	nv_wr32(dev, 0x00b140, 0xffffffff);
+-
+-	if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
+-		NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
+-		return -EBUSY;
+-	}
+-
+-	return 0;
+-}
+-
+-static int
+-nv40_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
+-{
+-	/*XXX: context save? */
+-	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+-	nv_wr32(dev, 0x00b140, 0x00000000);
+-	return 0;
+-}
+-
+-static int
+-nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+-{
+-	struct drm_device *dev = chan->dev;
+-	u32 inst = data << 4;
+-	u32 dma0 = nv_ri32(dev, inst + 0);
+-	u32 dma1 = nv_ri32(dev, inst + 4);
+-	u32 dma2 = nv_ri32(dev, inst + 8);
+-	u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
+-	u32 size = dma1 + 1;
+-
+-	/* only allow linear DMA objects */
+-	if (!(dma0 & 0x00002000))
+-		return -EINVAL;
+-
+-	if (mthd == 0x0190) {
+-		/* DMA_CMD */
+-		nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000));
+-		nv_wr32(dev, 0x00b334, base);
+-		nv_wr32(dev, 0x00b324, size);
+-	} else
+-	if (mthd == 0x01a0) {
+-		/* DMA_DATA */
+-		nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
+-		nv_wr32(dev, 0x00b360, base);
+-		nv_wr32(dev, 0x00b364, size);
+-	} else {
+-		/* DMA_IMAGE, VRAM only */
+-		if (dma0 & 0x000c0000)
+-			return -EINVAL;
+-
+-		nv_wr32(dev, 0x00b370, base);
+-		nv_wr32(dev, 0x00b374, size);
+-	}
+-
+-	return 0;
+-}
+-
+-static int
+-nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst)
+-{
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_gpuobj *ctx;
+-	unsigned long flags;
+-	int i;
+-
+-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
+-	for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+-		if (!dev_priv->channels.ptr[i])
+-			continue;
+-
+-		ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG];
+-		if (ctx && ctx->pinst == inst)
+-			break;
+-	}
+-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+-	return i;
+-}
+-
+-static void
+-nv40_vpe_set_tile_region(struct drm_device *dev, int i)
+-{
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+-
+-	nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch);
+-	nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit);
+-	nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr);
+-}
+-
+-static void
+-nv40_mpeg_isr(struct drm_device *dev)
+-{
+-	u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4;
+-	u32 chid = nv40_mpeg_isr_chid(dev, inst);
+-	u32 stat = nv_rd32(dev, 0x00b100);
+-	u32 type = nv_rd32(dev, 0x00b230);
+-	u32 mthd = nv_rd32(dev, 0x00b234);
+-	u32 data = nv_rd32(dev, 0x00b238);
+-	u32 show = stat;
+-
+-	if (stat & 0x01000000) {
+-		/* happens on initial binding of the object */
+-		if (type == 0x00000020 && mthd == 0x0000) {
+-			nv_mask(dev, 0x00b308, 0x00000000, 0x00000000);
+-			show &= ~0x01000000;
+-		}
+-
+-		if (type == 0x00000010) {
+-			if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data))
+-				show &= ~0x01000000;
+-		}
+-	}
+-
+-	nv_wr32(dev, 0x00b100, stat);
+-	nv_wr32(dev, 0x00b230, 0x00000001);
+-
+-	if (show && nouveau_ratelimit()) {
+-		NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+-			chid, inst, stat, type, mthd, data);
+-	}
+-}
+-
+-static void
+-nv40_vpe_isr(struct drm_device *dev)
+-{
+-	if (nv_rd32(dev, 0x00b100))
+-		nv40_mpeg_isr(dev);
+-
+-	if (nv_rd32(dev, 0x00b800)) {
+-		u32 stat = nv_rd32(dev, 0x00b800);
+-		NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
+-		nv_wr32(dev, 0xb800, stat);
+-	}
+-}
+-
+-static void
+-nv40_mpeg_destroy(struct drm_device *dev, int engine)
+-{
+-	struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine);
+-
+-	nouveau_irq_unregister(dev, 0);
+-
+-	NVOBJ_ENGINE_DEL(dev, MPEG);
+-	kfree(pmpeg);
+-}
+-
+-int
+-nv40_mpeg_create(struct drm_device *dev)
+-{
+-	struct nv40_mpeg_engine *pmpeg;
+-
+-	pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
+-	if (!pmpeg)
+-		return -ENOMEM;
+-
+-	pmpeg->base.destroy = nv40_mpeg_destroy;
+-	pmpeg->base.init = nv40_mpeg_init;
+-	pmpeg->base.fini = nv40_mpeg_fini;
+-	pmpeg->base.context_new = nv40_mpeg_context_new;
+-	pmpeg->base.context_del = nv40_mpeg_context_del;
+-	pmpeg->base.object_new = nv40_mpeg_object_new;
+-
+-	/* ISR vector, PMC_ENABLE bit,  and TILE regs are shared between
+-	 * all VPE engines, for this driver's purposes the PMPEG engine
+-	 * will be treated as the "master" and handle the global VPE
+-	 * bits too
+-	 */
+-	pmpeg->base.set_tile_region = nv40_vpe_set_tile_region;
+-	nouveau_irq_register(dev, 0, nv40_vpe_isr);
+-
+-	NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+-	NVOBJ_CLASS(dev, 0x3174, MPEG);
+-	NVOBJ_MTHD (dev, 0x3174, 0x0190, nv40_mpeg_mthd_dma);
+-	NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv40_mpeg_mthd_dma);
+-	NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv40_mpeg_mthd_dma);
+-
+-#if 0
+-	NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
+-	NVOBJ_CLASS(dev, 0x4075, ME);
+-#endif
+-	return 0;
+-
+-}
+diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c
+new file mode 100644
+index 0000000..e676b0d
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nv40_pm.c
+@@ -0,0 +1,348 @@
++/*
++ * Copyright 2011 Red Hat Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: Ben Skeggs
++ */
++
++#include "drmP.h"
++#include "nouveau_drv.h"
++#include "nouveau_bios.h"
++#include "nouveau_pm.h"
++#include "nouveau_hw.h"
++
++#define min2(a,b) ((a) < (b) ? (a) : (b))
++
++static u32
++read_pll_1(struct drm_device *dev, u32 reg)
++{
++	u32 ctrl = nv_rd32(dev, reg + 0x00);
++	int P = (ctrl & 0x00070000) >> 16;
++	int N = (ctrl & 0x0000ff00) >> 8;
++	int M = (ctrl & 0x000000ff) >> 0;
++	u32 ref = 27000, clk = 0;
++
++	if (ctrl & 0x80000000)
++		clk = ref * N / M;
++
++	return clk >> P;
++}
++
++static u32
++read_pll_2(struct drm_device *dev, u32 reg)
++{
++	u32 ctrl = nv_rd32(dev, reg + 0x00);
++	u32 coef = nv_rd32(dev, reg + 0x04);
++	int N2 = (coef & 0xff000000) >> 24;
++	int M2 = (coef & 0x00ff0000) >> 16;
++	int N1 = (coef & 0x0000ff00) >> 8;
++	int M1 = (coef & 0x000000ff) >> 0;
++	int P = (ctrl & 0x00070000) >> 16;
++	u32 ref = 27000, clk = 0;
++
++	if ((ctrl & 0x80000000) && M1) {
++		clk = ref * N1 / M1;
++		if ((ctrl & 0x40000100) == 0x40000000) {
++			if (M2)
++				clk = clk * N2 / M2;
++			else
++				clk = 0;
++		}
++	}
++
++	return clk >> P;
++}
++
++static u32
++read_clk(struct drm_device *dev, u32 src)
++{
++	switch (src) {
++	case 3:
++		return read_pll_2(dev, 0x004000);
++	case 2:
++		return read_pll_1(dev, 0x004008);
++	default:
++		break;
++	}
++
++	return 0;
++}
++
++int
++nv40_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
++{
++	u32 ctrl = nv_rd32(dev, 0x00c040);
++
++	perflvl->core   = read_clk(dev, (ctrl & 0x00000003) >> 0);
++	perflvl->shader = read_clk(dev, (ctrl & 0x00000030) >> 4);
++	perflvl->memory = read_pll_2(dev, 0x4020);
++	return 0;
++}
++
++struct nv40_pm_state {
++	u32 ctrl;
++	u32 npll_ctrl;
++	u32 npll_coef;
++	u32 spll;
++	u32 mpll_ctrl;
++	u32 mpll_coef;
++};
++
++static int
++nv40_calc_pll(struct drm_device *dev, u32 reg, struct pll_lims *pll,
++	      u32 clk, int *N1, int *M1, int *N2, int *M2, int *log2P)
++{
++	struct nouveau_pll_vals coef;
++	int ret;
++
++	ret = get_pll_limits(dev, reg, pll);
++	if (ret)
++		return ret;
++
++	if (clk < pll->vco1.maxfreq)
++		pll->vco2.maxfreq = 0;
++
++	ret = nouveau_calc_pll_mnp(dev, pll, clk, &coef);
++	if (ret == 0)
++		return -ERANGE;
++
++	*N1 = coef.N1;
++	*M1 = coef.M1;
++	if (N2 && M2) {
++		if (pll->vco2.maxfreq) {
++			*N2 = coef.N2;
++			*M2 = coef.M2;
++		} else {
++			*N2 = 1;
++			*M2 = 1;
++		}
++	}
++	*log2P = coef.log2P;
++	return 0;
++}
++
++void *
++nv40_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
++{
++	struct nv40_pm_state *info;
++	struct pll_lims pll;
++	int N1, N2, M1, M2, log2P;
++	int ret;
++
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return ERR_PTR(-ENOMEM);
++
++	/* core/geometric clock */
++	ret = nv40_calc_pll(dev, 0x004000, &pll, perflvl->core,
++			    &N1, &M1, &N2, &M2, &log2P);
++	if (ret < 0)
++		goto out;
++
++	if (N2 == M2) {
++		info->npll_ctrl = 0x80000100 | (log2P << 16);
++		info->npll_coef = (N1 << 8) | M1;
++	} else {
++		info->npll_ctrl = 0xc0000000 | (log2P << 16);
++		info->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
++	}
++
++	/* use the second PLL for shader/rop clock, if it differs from core */
++	if (perflvl->shader && perflvl->shader != perflvl->core) {
++		ret = nv40_calc_pll(dev, 0x004008, &pll, perflvl->shader,
++				    &N1, &M1, NULL, NULL, &log2P);
++		if (ret < 0)
++			goto out;
++
++		info->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1;
++		info->ctrl = 0x00000223;
++	} else {
++		info->spll = 0x00000000;
++		info->ctrl = 0x00000333;
++	}
++
++	/* memory clock */
++	if (!perflvl->memory) {
++		info->mpll_ctrl = 0x00000000;
++		goto out;
++	}
++
++	ret = nv40_calc_pll(dev, 0x004020, &pll, perflvl->memory,
++			    &N1, &M1, &N2, &M2, &log2P);
++	if (ret < 0)
++		goto out;
++
++	info->mpll_ctrl  = 0x80000000 | (log2P << 16);
++	info->mpll_ctrl |= min2(pll.log2p_bias + log2P, pll.max_log2p) << 20;
++	if (N2 == M2) {
++		info->mpll_ctrl |= 0x00000100;
++		info->mpll_coef  = (N1 << 8) | M1;
++	} else {
++		info->mpll_ctrl |= 0x40000000;
++		info->mpll_coef  = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
++	}
++
++out:
++	if (ret < 0) {
++		kfree(info);
++		info = ERR_PTR(ret);
++	}
++	return info;
++}
++
++static bool
++nv40_pm_gr_idle(void *data)
++{
++	struct drm_device *dev = data;
++
++	if ((nv_rd32(dev, 0x400760) & 0x000000f0) >> 4 !=
++	    (nv_rd32(dev, 0x400760) & 0x0000000f))
++		return false;
++
++	if (nv_rd32(dev, 0x400700))
++		return false;
++
++	return true;
++}
++
++void
++nv40_pm_clocks_set(struct drm_device *dev, void *pre_state)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nv40_pm_state *info = pre_state;
++	unsigned long flags;
++	struct bit_entry M;
++	u32 crtc_mask = 0;
++	u8 sr1[2];
++	int i;
++
++	/* determine which CRTCs are active, fetch VGA_SR1 for each */
++	for (i = 0; i < 2; i++) {
++		u32 vbl = nv_rd32(dev, 0x600808 + (i * 0x2000));
++		u32 cnt = 0;
++		do {
++			if (vbl != nv_rd32(dev, 0x600808 + (i * 0x2000))) {
++				nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01);
++				sr1[i] = nv_rd08(dev, 0x0c03c5 + (i * 0x2000));
++				if (!(sr1[i] & 0x20))
++					crtc_mask |= (1 << i);
++				break;
++			}
++			udelay(1);
++		} while (cnt++ < 32);
++	}
++
++	/* halt and idle engines */
++	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
++	nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
++	if (!nv_wait(dev, 0x002500, 0x00000010, 0x00000000))
++		goto resume;
++	nv_mask(dev, 0x003220, 0x00000001, 0x00000000);
++	if (!nv_wait(dev, 0x003220, 0x00000010, 0x00000000))
++		goto resume;
++	nv_mask(dev, 0x003200, 0x00000001, 0x00000000);
++	nv04_fifo_cache_pull(dev, false);
++
++	if (!nv_wait_cb(dev, nv40_pm_gr_idle, dev))
++		goto resume;
++
++	/* set engine clocks */
++	nv_mask(dev, 0x00c040, 0x00000333, 0x00000000);
++	nv_wr32(dev, 0x004004, info->npll_coef);
++	nv_mask(dev, 0x004000, 0xc0070100, info->npll_ctrl);
++	nv_mask(dev, 0x004008, 0xc007ffff, info->spll);
++	mdelay(5);
++	nv_mask(dev, 0x00c040, 0x00000333, info->ctrl);
++
++	if (!info->mpll_ctrl)
++		goto resume;
++
++	/* wait for vblank start on active crtcs, disable memory access */
++	for (i = 0; i < 2; i++) {
++		if (!(crtc_mask & (1 << i)))
++			continue;
++		nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000);
++		nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
++		nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01);
++		nv_wr08(dev, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20);
++	}
++
++	/* prepare ram for reclocking */
++	nv_wr32(dev, 0x1002d4, 0x00000001); /* precharge */
++	nv_wr32(dev, 0x1002d0, 0x00000001); /* refresh */
++	nv_wr32(dev, 0x1002d0, 0x00000001); /* refresh */
++	nv_mask(dev, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */
++	nv_wr32(dev, 0x1002dc, 0x00000001); /* enable self-refresh */
++
++	/* change the PLL of each memory partition */
++	nv_mask(dev, 0x00c040, 0x0000c000, 0x00000000);
++	switch (dev_priv->chipset) {
++	case 0x40:
++	case 0x45:
++	case 0x41:
++	case 0x42:
++	case 0x47:
++		nv_mask(dev, 0x004044, 0xc0771100, info->mpll_ctrl);
++		nv_mask(dev, 0x00402c, 0xc0771100, info->mpll_ctrl);
++		nv_wr32(dev, 0x004048, info->mpll_coef);
++		nv_wr32(dev, 0x004030, info->mpll_coef);
++	case 0x43:
++	case 0x49:
++	case 0x4b:
++		nv_mask(dev, 0x004038, 0xc0771100, info->mpll_ctrl);
++		nv_wr32(dev, 0x00403c, info->mpll_coef);
++	default:
++		nv_mask(dev, 0x004020, 0xc0771100, info->mpll_ctrl);
++		nv_wr32(dev, 0x004024, info->mpll_coef);
++		break;
++	}
++	udelay(100);
++	nv_mask(dev, 0x00c040, 0x0000c000, 0x0000c000);
++
++	/* re-enable normal operation of memory controller */
++	nv_wr32(dev, 0x1002dc, 0x00000000);
++	nv_mask(dev, 0x100210, 0x80000000, 0x80000000);
++	udelay(100);
++
++	/* execute memory reset script from vbios */
++	if (!bit_table(dev, 'M', &M))
++		nouveau_bios_init_exec(dev, ROM16(M.data[0]));
++
++	/* make sure we're in vblank (hopefully the same one as before), and
++	 * then re-enable crtc memory access
++	 */
++	for (i = 0; i < 2; i++) {
++		if (!(crtc_mask & (1 << i)))
++			continue;
++		nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
++		nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01);
++		nv_wr08(dev, 0x0c03c5 + (i * 0x2000), sr1[i]);
++	}
++
++	/* resume engines */
++resume:
++	nv_wr32(dev, 0x003250, 0x00000001);
++	nv_mask(dev, 0x003220, 0x00000001, 0x00000001);
++	nv_wr32(dev, 0x003200, 0x00000001);
++	nv_wr32(dev, 0x002500, 0x00000001);
++	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
++
++	kfree(info);
++}
+diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
+index 5d98907..882080e 100644
+--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
++++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
+@@ -329,8 +329,6 @@ nv50_crtc_destroy(struct drm_crtc *crtc)
+ 
+ 	drm_crtc_cleanup(&nv_crtc->base);
+ 
+-	nv50_cursor_fini(nv_crtc);
+-
+ 	nouveau_bo_unmap(nv_crtc->lut.nvbo);
+ 	nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
+ 	nouveau_bo_unmap(nv_crtc->cursor.nvbo);
+diff --git a/drivers/gpu/drm/nouveau/nv50_cursor.c b/drivers/gpu/drm/nouveau/nv50_cursor.c
+index 9752c35..adfc9b6 100644
+--- a/drivers/gpu/drm/nouveau/nv50_cursor.c
++++ b/drivers/gpu/drm/nouveau/nv50_cursor.c
+@@ -137,21 +137,3 @@ nv50_cursor_init(struct nouveau_crtc *nv_crtc)
+ 	nv_crtc->cursor.show = nv50_cursor_show;
+ 	return 0;
+ }
+-
+-void
+-nv50_cursor_fini(struct nouveau_crtc *nv_crtc)
+-{
+-	struct drm_device *dev = nv_crtc->base.dev;
+-	int idx = nv_crtc->index;
+-
+-	NV_DEBUG_KMS(dev, "\n");
+-
+-	nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), 0);
+-	if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx),
+-		     NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
+-		NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
+-		NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
+-			 nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx)));
+-	}
+-}
+-
+diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
+index db1a5f4..d23ca00 100644
+--- a/drivers/gpu/drm/nouveau/nv50_display.c
++++ b/drivers/gpu/drm/nouveau/nv50_display.c
+@@ -247,6 +247,16 @@ static int nv50_display_disable(struct drm_device *dev)
+ 		}
+ 	}
+ 
++	for (i = 0; i < 2; i++) {
++		nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0);
++		if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
++			     NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
++			NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
++			NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
++				 nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
++		}
++	}
++
+ 	nv50_evo_fini(dev);
+ 
+ 	for (i = 0; i < 3; i++) {
+@@ -286,23 +296,6 @@ int nv50_display_create(struct drm_device *dev)
+ 		return -ENOMEM;
+ 	dev_priv->engine.display.priv = priv;
+ 
+-	/* init basic kernel modesetting */
+-	drm_mode_config_init(dev);
+-
+-	/* Initialise some optional connector properties. */
+-	drm_mode_create_scaling_mode_property(dev);
+-	drm_mode_create_dithering_property(dev);
+-
+-	dev->mode_config.min_width = 0;
+-	dev->mode_config.min_height = 0;
+-
+-	dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs;
+-
+-	dev->mode_config.max_width = 8192;
+-	dev->mode_config.max_height = 8192;
+-
+-	dev->mode_config.fb_base = dev_priv->fb_phys;
+-
+ 	/* Create CRTC objects */
+ 	for (i = 0; i < 2; i++)
+ 		nv50_crtc_create(dev, i);
+@@ -364,8 +357,6 @@ nv50_display_destroy(struct drm_device *dev)
+ 
+ 	NV_DEBUG_KMS(dev, "\n");
+ 
+-	drm_mode_config_cleanup(dev);
+-
+ 	nv50_display_disable(dev);
+ 	nouveau_irq_unregister(dev, 26);
+ 	kfree(disp);
+@@ -698,7 +689,7 @@ nv50_display_unk10_handler(struct drm_device *dev)
+ 		struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
+ 
+ 		if (dcb->type == type && (dcb->or & (1 << or))) {
+-			nouveau_bios_run_display_table(dev, dcb, 0, -1);
++			nouveau_bios_run_display_table(dev, 0, -1, dcb, -1);
+ 			disp->irq.dcb = dcb;
+ 			goto ack;
+ 		}
+@@ -711,37 +702,6 @@ ack:
+ }
+ 
+ static void
+-nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb)
+-{
+-	int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
+-	struct drm_encoder *encoder;
+-	uint32_t tmp, unk0 = 0, unk1 = 0;
+-
+-	if (dcb->type != OUTPUT_DP)
+-		return;
+-
+-	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+-		struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+-
+-		if (nv_encoder->dcb == dcb) {
+-			unk0 = nv_encoder->dp.unk0;
+-			unk1 = nv_encoder->dp.unk1;
+-			break;
+-		}
+-	}
+-
+-	if (unk0 || unk1) {
+-		tmp  = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
+-		tmp &= 0xfffffe03;
+-		nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp | unk0);
+-
+-		tmp  = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link));
+-		tmp &= 0xfef080c0;
+-		nv_wr32(dev, NV50_SOR_DP_UNK128(or, link), tmp | unk1);
+-	}
+-}
+-
+-static void
+ nv50_display_unk20_handler(struct drm_device *dev)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+@@ -753,7 +713,7 @@ nv50_display_unk20_handler(struct drm_device *dev)
+ 	NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
+ 	dcb = disp->irq.dcb;
+ 	if (dcb) {
+-		nouveau_bios_run_display_table(dev, dcb, 0, -2);
++		nouveau_bios_run_display_table(dev, 0, -2, dcb, -1);
+ 		disp->irq.dcb = NULL;
+ 	}
+ 
+@@ -837,9 +797,15 @@ nv50_display_unk20_handler(struct drm_device *dev)
+ 	}
+ 
+ 	script = nv50_display_script_select(dev, dcb, mc, pclk);
+-	nouveau_bios_run_display_table(dev, dcb, script, pclk);
++	nouveau_bios_run_display_table(dev, script, pclk, dcb, -1);
+ 
+-	nv50_display_unk20_dp_hack(dev, dcb);
++	if (type == OUTPUT_DP) {
++		int link = !(dcb->dpconf.sor.link & 1);
++		if ((mc & 0x000f0000) == 0x00020000)
++			nouveau_dp_tu_update(dev, or, link, pclk, 18);
++		else
++			nouveau_dp_tu_update(dev, or, link, pclk, 24);
++	}
+ 
+ 	if (dcb->type != OUTPUT_ANALOG) {
+ 		tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or));
+@@ -904,7 +870,7 @@ nv50_display_unk40_handler(struct drm_device *dev)
+ 	if (!dcb)
+ 		goto ack;
+ 
+-	nouveau_bios_run_display_table(dev, dcb, script, -pclk);
++	nouveau_bios_run_display_table(dev, script, -pclk, dcb, -1);
+ 	nv50_display_unk40_dp_set_tmds(dev, dcb);
+ 
+ ack:
+diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c
+index d4f4206..793a5cc 100644
+--- a/drivers/gpu/drm/nouveau/nv50_gpio.c
++++ b/drivers/gpu/drm/nouveau/nv50_gpio.c
+@@ -98,6 +98,37 @@ nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
+ }
+ 
+ int
++nvd0_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
++{
++	struct dcb_gpio_entry *gpio;
++	u32 v;
++
++	gpio = nouveau_bios_gpio_entry(dev, tag);
++	if (!gpio)
++		return -ENOENT;
++
++	v  = nv_rd32(dev, 0x00d610 + (gpio->line * 4));
++	v &= 0x00004000;
++	return (!!v == (gpio->state[1] & 1));
++}
++
++int
++nvd0_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
++{
++	struct dcb_gpio_entry *gpio;
++	u32 v;
++
++	gpio = nouveau_bios_gpio_entry(dev, tag);
++	if (!gpio)
++		return -ENOENT;
++
++	v = gpio->state[state] ^ 2;
++
++	nv_mask(dev, 0x00d610 + (gpio->line * 4), 0x00003000, v << 12);
++	return 0;
++}
++
++int
+ nv50_gpio_irq_register(struct drm_device *dev, enum dcb_gpio_tag tag,
+ 		       void (*handler)(void *, int), void *data)
+ {
+diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
+index d43c46c..8c979b3 100644
+--- a/drivers/gpu/drm/nouveau/nv50_graph.c
++++ b/drivers/gpu/drm/nouveau/nv50_graph.c
+@@ -120,70 +120,62 @@ nv50_graph_unload_context(struct drm_device *dev)
+ 	return 0;
+ }
+ 
+-static void
+-nv50_graph_init_reset(struct drm_device *dev)
+-{
+-	uint32_t pmc_e = NV_PMC_ENABLE_PGRAPH | (1 << 21);
+-	NV_DEBUG(dev, "\n");
+-
+-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~pmc_e);
+-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |  pmc_e);
+-}
+-
+-static void
+-nv50_graph_init_intr(struct drm_device *dev)
+-{
+-	NV_DEBUG(dev, "\n");
+-
+-	nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff);
+-	nv_wr32(dev, 0x400138, 0xffffffff);
+-	nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff);
+-}
+-
+-static void
+-nv50_graph_init_regs__nv(struct drm_device *dev)
++static int
++nv50_graph_init(struct drm_device *dev, int engine)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	uint32_t units = nv_rd32(dev, 0x1540);
++	struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
++	u32 units = nv_rd32(dev, 0x001540);
+ 	int i;
+ 
+ 	NV_DEBUG(dev, "\n");
+ 
++	/* master reset */
++	nv_mask(dev, 0x000200, 0x00200100, 0x00000000);
++	nv_mask(dev, 0x000200, 0x00200100, 0x00200100);
++	nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */
++
++	/* reset/enable traps and interrupts */
+ 	nv_wr32(dev, 0x400804, 0xc0000000);
+ 	nv_wr32(dev, 0x406800, 0xc0000000);
+ 	nv_wr32(dev, 0x400c04, 0xc0000000);
+ 	nv_wr32(dev, 0x401800, 0xc0000000);
+ 	nv_wr32(dev, 0x405018, 0xc0000000);
+ 	nv_wr32(dev, 0x402000, 0xc0000000);
+-
+ 	for (i = 0; i < 16; i++) {
+-		if (units & 1 << i) {
+-			if (dev_priv->chipset < 0xa0) {
+-				nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000);
+-				nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000);
+-				nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000);
+-			} else {
+-				nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000);
+-				nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000);
+-				nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000);
+-			}
++		if (!(units & (1 << i)))
++			continue;
++
++		if (dev_priv->chipset < 0xa0) {
++			nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000);
++			nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000);
++			nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000);
++		} else {
++			nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000);
++			nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000);
++			nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000);
+ 		}
+ 	}
+ 
+ 	nv_wr32(dev, 0x400108, 0xffffffff);
+-
+-	nv_wr32(dev, 0x400824, 0x00004000);
++	nv_wr32(dev, 0x400138, 0xffffffff);
++	nv_wr32(dev, 0x400100, 0xffffffff);
++	nv_wr32(dev, 0x40013c, 0xffffffff);
+ 	nv_wr32(dev, 0x400500, 0x00010001);
+-}
+-
+-static void
+-nv50_graph_init_zcull(struct drm_device *dev)
+-{
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	int i;
+-
+-	NV_DEBUG(dev, "\n");
+ 
++	/* upload context program, initialise ctxctl defaults */
++	nv_wr32(dev, 0x400324, 0x00000000);
++	for (i = 0; i < pgraph->ctxprog_size; i++)
++		nv_wr32(dev, 0x400328, pgraph->ctxprog[i]);
++	nv_wr32(dev, 0x400824, 0x00000000);
++	nv_wr32(dev, 0x400828, 0x00000000);
++	nv_wr32(dev, 0x40082c, 0x00000000);
++	nv_wr32(dev, 0x400830, 0x00000000);
++	nv_wr32(dev, 0x400724, 0x00000000);
++	nv_wr32(dev, 0x40032c, 0x00000000);
++	nv_wr32(dev, 0x400320, 4);	/* CTXCTL_CMD = NEWCTXDMA */
++
++	/* some unknown zcull magic */
+ 	switch (dev_priv->chipset & 0xf0) {
+ 	case 0x50:
+ 	case 0x80:
+@@ -212,43 +204,7 @@ nv50_graph_init_zcull(struct drm_device *dev)
+ 		nv_wr32(dev, 0x402c28 + (i * 8), 0x00000000);
+ 		nv_wr32(dev, 0x402c2c + (i * 8), 0x00000000);
+ 	}
+-}
+-
+-static int
+-nv50_graph_init_ctxctl(struct drm_device *dev)
+-{
+-	struct nv50_graph_engine *pgraph = nv_engine(dev, NVOBJ_ENGINE_GR);
+-	int i;
+-
+-	NV_DEBUG(dev, "\n");
+-
+-	nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+-	for (i = 0; i < pgraph->ctxprog_size; i++)
+-		nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, pgraph->ctxprog[i]);
+-
+-	nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */
+-	nv_wr32(dev, 0x400320, 4);
+-	nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0);
+-	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, 0);
+-	return 0;
+-}
+-
+-static int
+-nv50_graph_init(struct drm_device *dev, int engine)
+-{
+-	int ret;
+-
+-	NV_DEBUG(dev, "\n");
+-
+-	nv50_graph_init_reset(dev);
+-	nv50_graph_init_regs__nv(dev);
+-	nv50_graph_init_zcull(dev);
+-
+-	ret = nv50_graph_init_ctxctl(dev);
+-	if (ret)
+-		return ret;
+ 
+-	nv50_graph_init_intr(dev);
+ 	return 0;
+ }
+ 
+diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c
+index de9abff..d05c2c3 100644
+--- a/drivers/gpu/drm/nouveau/nv50_grctx.c
++++ b/drivers/gpu/drm/nouveau/nv50_grctx.c
+@@ -40,6 +40,12 @@
+ #define CP_FLAG_UNK0B                 ((0 * 32) + 0xb)
+ #define CP_FLAG_UNK0B_CLEAR           0
+ #define CP_FLAG_UNK0B_SET             1
++#define CP_FLAG_XFER_SWITCH           ((0 * 32) + 0xe)
++#define CP_FLAG_XFER_SWITCH_DISABLE   0
++#define CP_FLAG_XFER_SWITCH_ENABLE    1
++#define CP_FLAG_STATE                 ((0 * 32) + 0x1c)
++#define CP_FLAG_STATE_STOPPED         0
++#define CP_FLAG_STATE_RUNNING         1
+ #define CP_FLAG_UNK1D                 ((0 * 32) + 0x1d)
+ #define CP_FLAG_UNK1D_CLEAR           0
+ #define CP_FLAG_UNK1D_SET             1
+@@ -194,6 +200,9 @@ nv50_grctx_init(struct nouveau_grctx *ctx)
+ 				   "the devs.\n");
+ 		return -ENOSYS;
+ 	}
++
++	cp_set (ctx, STATE, RUNNING);
++	cp_set (ctx, XFER_SWITCH, ENABLE);
+ 	/* decide whether we're loading/unloading the context */
+ 	cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
+ 	cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);
+@@ -260,6 +269,8 @@ nv50_grctx_init(struct nouveau_grctx *ctx)
+ 	cp_name(ctx, cp_exit);
+ 	cp_set (ctx, USER_SAVE, NOT_PENDING);
+ 	cp_set (ctx, USER_LOAD, NOT_PENDING);
++	cp_set (ctx, XFER_SWITCH, DISABLE);
++	cp_set (ctx, STATE, STOPPED);
+ 	cp_out (ctx, CP_END);
+ 	ctx->ctxvals_pos += 0x400; /* padding... no idea why you need it */
+ 
+diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
+index 8a28100..3d5a86b 100644
+--- a/drivers/gpu/drm/nouveau/nv50_pm.c
++++ b/drivers/gpu/drm/nouveau/nv50_pm.c
+@@ -115,15 +115,15 @@ nv50_pm_clock_set(struct drm_device *dev, void *pre_state)
+ 	    BIT_M.version == 1 && BIT_M.length >= 0x0b) {
+ 		script = ROM16(BIT_M.data[0x05]);
+ 		if (script)
+-			nouveau_bios_run_init_table(dev, script, NULL);
++			nouveau_bios_run_init_table(dev, script, NULL, -1);
+ 		script = ROM16(BIT_M.data[0x07]);
+ 		if (script)
+-			nouveau_bios_run_init_table(dev, script, NULL);
++			nouveau_bios_run_init_table(dev, script, NULL, -1);
+ 		script = ROM16(BIT_M.data[0x09]);
+ 		if (script)
+-			nouveau_bios_run_init_table(dev, script, NULL);
++			nouveau_bios_run_init_table(dev, script, NULL, -1);
+ 
+-		nouveau_bios_run_init_table(dev, perflvl->memscript, NULL);
++		nouveau_bios_run_init_table(dev, perflvl->memscript, NULL, -1);
+ 	}
+ 
+ 	if (state->type == PLL_MEMORY) {
+diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
+index ffe8b48..2633aa8 100644
+--- a/drivers/gpu/drm/nouveau/nv50_sor.c
++++ b/drivers/gpu/drm/nouveau/nv50_sor.c
+@@ -124,7 +124,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
+ 		if (mode == DRM_MODE_DPMS_ON) {
+ 			u8 status = DP_SET_POWER_D0;
+ 			nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
+-			nouveau_dp_link_train(encoder);
++			nouveau_dp_link_train(encoder, nv_encoder->dp.datarate);
+ 		} else {
+ 			u8 status = DP_SET_POWER_D3;
+ 			nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
+@@ -187,14 +187,13 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
+ 	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ 	struct drm_device *dev = encoder->dev;
+ 	struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc);
++	struct nouveau_connector *nv_connector;
+ 	uint32_t mode_ctl = 0;
+ 	int ret;
+ 
+ 	NV_DEBUG_KMS(dev, "or %d type %d -> crtc %d\n",
+ 		     nv_encoder->or, nv_encoder->dcb->type, crtc->index);
+ 
+-	nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON);
+-
+ 	switch (nv_encoder->dcb->type) {
+ 	case OUTPUT_TMDS:
+ 		if (nv_encoder->dcb->sorconf.link & 1) {
+@@ -206,7 +205,15 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
+ 			mode_ctl = 0x0200;
+ 		break;
+ 	case OUTPUT_DP:
+-		mode_ctl |= (nv_encoder->dp.mc_unknown << 16);
++		nv_connector = nouveau_encoder_connector_get(nv_encoder);
++		if (nv_connector && nv_connector->base.display_info.bpc == 6) {
++			nv_encoder->dp.datarate = crtc->mode->clock * 18 / 8;
++			mode_ctl |= 0x00020000;
++		} else {
++			nv_encoder->dp.datarate = crtc->mode->clock * 24 / 8;
++			mode_ctl |= 0x00050000;
++		}
++
+ 		if (nv_encoder->dcb->sorconf.link & 1)
+ 			mode_ctl |= 0x00000800;
+ 		else
+@@ -227,6 +234,8 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
+ 	if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+ 		mode_ctl |= NV50_EVO_SOR_MODE_CTRL_NVSYNC;
+ 
++	nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON);
++
+ 	ret = RING_SPACE(evo, 2);
+ 	if (ret) {
+ 		NV_ERROR(dev, "no space while connecting SOR\n");
+@@ -313,31 +322,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
+ 	encoder->possible_crtcs = entry->heads;
+ 	encoder->possible_clones = 0;
+ 
+-	if (nv_encoder->dcb->type == OUTPUT_DP) {
+-		int or = nv_encoder->or, link = !(entry->dpconf.sor.link & 1);
+-		uint32_t tmp;
+-
+-		tmp = nv_rd32(dev, 0x61c700 + (or * 0x800));
+-		if (!tmp)
+-			tmp = nv_rd32(dev, 0x610798 + (or * 8));
+-
+-		switch ((tmp & 0x00000f00) >> 8) {
+-		case 8:
+-		case 9:
+-			nv_encoder->dp.mc_unknown = (tmp & 0x000f0000) >> 16;
+-			tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
+-			nv_encoder->dp.unk0 = tmp & 0x000001fc;
+-			tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link));
+-			nv_encoder->dp.unk1 = tmp & 0x010f7f3f;
+-			break;
+-		default:
+-			break;
+-		}
+-
+-		if (!nv_encoder->dp.mc_unknown)
+-			nv_encoder->dp.mc_unknown = 5;
+-	}
+-
+ 	drm_mode_connector_attach_encoder(connector, encoder);
+ 	return 0;
+ }
+diff --git a/drivers/gpu/drm/nouveau/nv50_vram.c b/drivers/gpu/drm/nouveau/nv50_vram.c
+index af32dae..9da2383 100644
+--- a/drivers/gpu/drm/nouveau/nv50_vram.c
++++ b/drivers/gpu/drm/nouveau/nv50_vram.c
+@@ -51,7 +51,7 @@ void
+ nv50_vram_del(struct drm_device *dev, struct nouveau_mem **pmem)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_mm *mm = dev_priv->engine.vram.mm;
++	struct nouveau_mm *mm = &dev_priv->engine.vram.mm;
+ 	struct nouveau_mm_node *this;
+ 	struct nouveau_mem *mem;
+ 
+@@ -82,7 +82,7 @@ nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 size_nc,
+ 	      u32 memtype, struct nouveau_mem **pmem)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_mm *mm = dev_priv->engine.vram.mm;
++	struct nouveau_mm *mm = &dev_priv->engine.vram.mm;
+ 	struct nouveau_mm_node *r;
+ 	struct nouveau_mem *mem;
+ 	int comp = (memtype & 0x300) >> 8;
+diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c
+index e4b2b9e..618c144 100644
+--- a/drivers/gpu/drm/nouveau/nva3_pm.c
++++ b/drivers/gpu/drm/nouveau/nva3_pm.c
+@@ -27,178 +27,316 @@
+ #include "nouveau_bios.h"
+ #include "nouveau_pm.h"
+ 
+-/* This is actually a lot more complex than it appears here, but hopefully
+- * this should be able to deal with what the VBIOS leaves for us..
+- *
+- * If not, well, I'll jump off that bridge when I come to it.
+- */
++static u32 read_clk(struct drm_device *, int, bool);
++static u32 read_pll(struct drm_device *, int, u32);
+ 
+-struct nva3_pm_state {
+-	enum pll_types type;
+-	u32 src0;
+-	u32 src1;
+-	u32 ctrl;
+-	u32 coef;
+-	u32 old_pnm;
+-	u32 new_pnm;
+-	u32 new_div;
+-};
++static u32
++read_vco(struct drm_device *dev, int clk)
++{
++	u32 sctl = nv_rd32(dev, 0x4120 + (clk * 4));
++	if ((sctl & 0x00000030) != 0x00000030)
++		return read_pll(dev, 0x41, 0x00e820);
++	return read_pll(dev, 0x42, 0x00e8a0);
++}
+ 
+-static int
+-nva3_pm_pll_offset(u32 id)
++static u32
++read_clk(struct drm_device *dev, int clk, bool ignore_en)
+ {
+-	static const u32 pll_map[] = {
+-		0x00, PLL_CORE,
+-		0x01, PLL_SHADER,
+-		0x02, PLL_MEMORY,
+-		0x00, 0x00
+-	};
+-	const u32 *map = pll_map;
+-
+-	while (map[1]) {
+-		if (id == map[1])
+-			return map[0];
+-		map += 2;
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	u32 sctl, sdiv, sclk;
++
++	/* refclk for the 0xe8xx plls is a fixed frequency */
++	if (clk >= 0x40) {
++		if (dev_priv->chipset == 0xaf) {
++			/* no joke.. seriously.. sigh.. */
++			return nv_rd32(dev, 0x00471c) * 1000;
++		}
++
++		return dev_priv->crystal;
+ 	}
+ 
+-	return -ENOENT;
++	sctl = nv_rd32(dev, 0x4120 + (clk * 4));
++	if (!ignore_en && !(sctl & 0x00000100))
++		return 0;
++
++	switch (sctl & 0x00003000) {
++	case 0x00000000:
++		return dev_priv->crystal;
++	case 0x00002000:
++		if (sctl & 0x00000040)
++			return 108000;
++		return 100000;
++	case 0x00003000:
++		sclk = read_vco(dev, clk);
++		sdiv = ((sctl & 0x003f0000) >> 16) + 2;
++		return (sclk * 2) / sdiv;
++	default:
++		return 0;
++	}
+ }
+ 
+-int
+-nva3_pm_clock_get(struct drm_device *dev, u32 id)
++static u32
++read_pll(struct drm_device *dev, int clk, u32 pll)
++{
++	u32 ctrl = nv_rd32(dev, pll + 0);
++	u32 sclk = 0, P = 1, N = 1, M = 1;
++
++	if (!(ctrl & 0x00000008)) {
++		if (ctrl & 0x00000001) {
++			u32 coef = nv_rd32(dev, pll + 4);
++			M = (coef & 0x000000ff) >> 0;
++			N = (coef & 0x0000ff00) >> 8;
++			P = (coef & 0x003f0000) >> 16;
++
++			/* no post-divider on these.. */
++			if ((pll & 0x00ff00) == 0x00e800)
++				P = 1;
++
++			sclk = read_clk(dev, 0x00 + clk, false);
++		}
++	} else {
++		sclk = read_clk(dev, 0x10 + clk, false);
++	}
++
++	return sclk * N / (M * P);
++}
++
++struct creg {
++	u32 clk;
++	u32 pll;
++};
++
++static int
++calc_clk(struct drm_device *dev, int clk, u32 pll, u32 khz, struct creg *reg)
+ {
+-	u32 src0, src1, ctrl, coef;
+-	struct pll_lims pll;
+-	int ret, off;
+-	int P, N, M;
++	struct pll_lims limits;
++	u32 oclk, sclk, sdiv;
++	int P, N, M, diff;
++	int ret;
++
++	reg->pll = 0;
++	reg->clk = 0;
++	if (!khz) {
++		NV_DEBUG(dev, "no clock for 0x%04x/0x%02x\n", pll, clk);
++		return 0;
++	}
+ 
+-	ret = get_pll_limits(dev, id, &pll);
++	switch (khz) {
++	case 27000:
++		reg->clk = 0x00000100;
++		return khz;
++	case 100000:
++		reg->clk = 0x00002100;
++		return khz;
++	case 108000:
++		reg->clk = 0x00002140;
++		return khz;
++	default:
++		sclk = read_vco(dev, clk);
++		sdiv = min((sclk * 2) / (khz - 2999), (u32)65);
++		/* if the clock has a PLL attached, and we can get a within
++		 * [-2, 3) MHz of a divider, we'll disable the PLL and use
++		 * the divider instead.
++		 *
++		 * divider can go as low as 2, limited here because NVIDIA
++		 * and the VBIOS on my NVA8 seem to prefer using the PLL
++		 * for 810MHz - is there a good reason?
++		 */
++		if (sdiv > 4) {
++			oclk = (sclk * 2) / sdiv;
++			diff = khz - oclk;
++			if (!pll || (diff >= -2000 && diff < 3000)) {
++				reg->clk = (((sdiv - 2) << 16) | 0x00003100);
++				return oclk;
++			}
++		}
++
++		if (!pll) {
++			NV_ERROR(dev, "bad freq %02x: %d %d\n", clk, khz, sclk);
++			return -ERANGE;
++		}
++
++		break;
++	}
++
++	ret = get_pll_limits(dev, pll, &limits);
+ 	if (ret)
+ 		return ret;
+ 
+-	off = nva3_pm_pll_offset(id);
+-	if (off < 0)
+-		return off;
++	limits.refclk = read_clk(dev, clk - 0x10, true);
++	if (!limits.refclk)
++		return -EINVAL;
++
++	ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P);
++	if (ret >= 0) {
++		reg->clk = nv_rd32(dev, 0x4120 + (clk * 4));
++		reg->pll = (P << 16) | (N << 8) | M;
++	}
++	return ret;
++}
++
++static void
++prog_pll(struct drm_device *dev, int clk, u32 pll, struct creg *reg)
++{
++	const u32 src0 = 0x004120 + (clk * 4);
++	const u32 src1 = 0x004160 + (clk * 4);
++	const u32 ctrl = pll + 0;
++	const u32 coef = pll + 4;
++	u32 cntl;
++
++	if (!reg->clk && !reg->pll) {
++		NV_DEBUG(dev, "no clock for %02x\n", clk);
++		return;
++	}
+ 
+-	src0 = nv_rd32(dev, 0x4120 + (off * 4));
+-	src1 = nv_rd32(dev, 0x4160 + (off * 4));
+-	ctrl = nv_rd32(dev, pll.reg + 0);
+-	coef = nv_rd32(dev, pll.reg + 4);
+-	NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+-		      id, src0, src1, ctrl, coef);
++	cntl = nv_rd32(dev, ctrl) & 0xfffffff2;
++	if (reg->pll) {
++		nv_mask(dev, src0, 0x00000101, 0x00000101);
++		nv_wr32(dev, coef, reg->pll);
++		nv_wr32(dev, ctrl, cntl | 0x00000015);
++		nv_mask(dev, src1, 0x00000100, 0x00000000);
++		nv_mask(dev, src1, 0x00000001, 0x00000000);
++	} else {
++		nv_mask(dev, src1, 0x003f3141, 0x00000101 | reg->clk);
++		nv_wr32(dev, ctrl, cntl | 0x0000001d);
++		nv_mask(dev, ctrl, 0x00000001, 0x00000000);
++		nv_mask(dev, src0, 0x00000100, 0x00000000);
++		nv_mask(dev, src0, 0x00000001, 0x00000000);
++	}
++}
+ 
+-	if (ctrl & 0x00000008) {
+-		u32 div = ((src1 & 0x003c0000) >> 18) + 1;
+-		return (pll.refclk * 2) / div;
++static void
++prog_clk(struct drm_device *dev, int clk, struct creg *reg)
++{
++	if (!reg->clk) {
++		NV_DEBUG(dev, "no clock for %02x\n", clk);
++		return;
+ 	}
+ 
+-	P = (coef & 0x003f0000) >> 16;
+-	N = (coef & 0x0000ff00) >> 8;
+-	M = (coef & 0x000000ff);
+-	return pll.refclk * N / M / P;
++	nv_mask(dev, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | reg->clk);
++}
++
++int
++nva3_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
++{
++	perflvl->core   = read_pll(dev, 0x00, 0x4200);
++	perflvl->shader = read_pll(dev, 0x01, 0x4220);
++	perflvl->memory = read_pll(dev, 0x02, 0x4000);
++	perflvl->unka0  = read_clk(dev, 0x20, false);
++	perflvl->vdec   = read_clk(dev, 0x21, false);
++	perflvl->daemon = read_clk(dev, 0x25, false);
++	perflvl->copy   = perflvl->core;
++	return 0;
+ }
+ 
++struct nva3_pm_state {
++	struct creg nclk;
++	struct creg sclk;
++	struct creg mclk;
++	struct creg vdec;
++	struct creg unka0;
++};
++
+ void *
+-nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+-		  u32 id, int khz)
++nva3_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
+ {
+-	struct nva3_pm_state *pll;
+-	struct pll_lims limits;
+-	int N, M, P, diff;
+-	int ret, off;
++	struct nva3_pm_state *info;
++	int ret;
+ 
+-	ret = get_pll_limits(dev, id, &limits);
++	info = kzalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return ERR_PTR(-ENOMEM);
++
++	ret = calc_clk(dev, 0x10, 0x4200, perflvl->core, &info->nclk);
+ 	if (ret < 0)
+-		return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
++		goto out;
+ 
+-	off = nva3_pm_pll_offset(id);
+-	if (id < 0)
+-		return ERR_PTR(-EINVAL);
++	ret = calc_clk(dev, 0x11, 0x4220, perflvl->shader, &info->sclk);
++	if (ret < 0)
++		goto out;
+ 
++	ret = calc_clk(dev, 0x12, 0x4000, perflvl->memory, &info->mclk);
++	if (ret < 0)
++		goto out;
+ 
+-	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+-	if (!pll)
+-		return ERR_PTR(-ENOMEM);
+-	pll->type = id;
+-	pll->src0 = 0x004120 + (off * 4);
+-	pll->src1 = 0x004160 + (off * 4);
+-	pll->ctrl = limits.reg + 0;
+-	pll->coef = limits.reg + 4;
+-
+-	/* If target clock is within [-2, 3) MHz of a divisor, we'll
+-	 * use that instead of calculating MNP values
+-	 */
+-	pll->new_div = min((limits.refclk * 2) / (khz - 2999), 16);
+-	if (pll->new_div) {
+-		diff = khz - ((limits.refclk * 2) / pll->new_div);
+-		if (diff < -2000 || diff >= 3000)
+-			pll->new_div = 0;
+-	}
++	ret = calc_clk(dev, 0x20, 0x0000, perflvl->unka0, &info->unka0);
++	if (ret < 0)
++		goto out;
+ 
+-	if (!pll->new_div) {
+-		ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P);
+-		if (ret < 0)
+-			return ERR_PTR(ret);
++	ret = calc_clk(dev, 0x21, 0x0000, perflvl->vdec, &info->vdec);
++	if (ret < 0)
++		goto out;
+ 
+-		pll->new_pnm = (P << 16) | (N << 8) | M;
+-		pll->new_div = 2 - 1;
+-	} else {
+-		pll->new_pnm = 0;
+-		pll->new_div--;
++out:
++	if (ret < 0) {
++		kfree(info);
++		info = ERR_PTR(ret);
+ 	}
++	return info;
++}
++
++static bool
++nva3_pm_grcp_idle(void *data)
++{
++	struct drm_device *dev = data;
+ 
+-	if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101)
+-		pll->old_pnm = nv_rd32(dev, pll->coef);
+-	return pll;
++	if (!(nv_rd32(dev, 0x400304) & 0x00000001))
++		return true;
++	if (nv_rd32(dev, 0x400308) == 0x0050001c)
++		return true;
++	return false;
+ }
+ 
+ void
+-nva3_pm_clock_set(struct drm_device *dev, void *pre_state)
++nva3_pm_clocks_set(struct drm_device *dev, void *pre_state)
+ {
+-	struct nva3_pm_state *pll = pre_state;
+-	u32 ctrl = 0;
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nva3_pm_state *info = pre_state;
++	unsigned long flags;
+ 
+-	/* For the memory clock, NVIDIA will build a "script" describing
+-	 * the reclocking process and ask PDAEMON to execute it.
+-	 */
+-	if (pll->type == PLL_MEMORY) {
+-		nv_wr32(dev, 0x100210, 0);
+-		nv_wr32(dev, 0x1002dc, 1);
+-		nv_wr32(dev, 0x004018, 0x00001000);
+-		ctrl = 0x18000100;
++	/* prevent any new grctx switches from starting */
++	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
++	nv_wr32(dev, 0x400324, 0x00000000);
++	nv_wr32(dev, 0x400328, 0x0050001c); /* wait flag 0x1c */
++	/* wait for any pending grctx switches to complete */
++	if (!nv_wait_cb(dev, nva3_pm_grcp_idle, dev)) {
++		NV_ERROR(dev, "pm: ctxprog didn't go idle\n");
++		goto cleanup;
+ 	}
+-
+-	if (pll->old_pnm || !pll->new_pnm) {
+-		nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 |
+-						    (pll->new_div << 18));
+-		nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
+-		nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
++	/* freeze PFIFO */
++	nv_mask(dev, 0x002504, 0x00000001, 0x00000001);
++	if (!nv_wait(dev, 0x002504, 0x00000010, 0x00000010)) {
++		NV_ERROR(dev, "pm: fifo didn't go idle\n");
++		goto cleanup;
+ 	}
+ 
+-	if (pll->new_pnm) {
+-		nv_mask(dev, pll->src0, 0x00000101, 0x00000101);
+-		nv_wr32(dev, pll->coef, pll->new_pnm);
+-		nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
+-		nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000);
+-		nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010);
+-		nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl);
+-		nv_mask(dev, pll->src1, 0x00000100, 0x00000000);
+-		nv_mask(dev, pll->src1, 0x00000001, 0x00000000);
+-		if (pll->type == PLL_MEMORY)
+-			nv_wr32(dev, 0x4018, 0x10005000);
+-	} else {
+-		nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
+-		nv_mask(dev, pll->src0, 0x00000100, 0x00000000);
+-		nv_mask(dev, pll->src0, 0x00000001, 0x00000000);
+-		if (pll->type == PLL_MEMORY)
+-			nv_wr32(dev, 0x4018, 0x1000d000);
+-	}
++	prog_pll(dev, 0x00, 0x004200, &info->nclk);
++	prog_pll(dev, 0x01, 0x004220, &info->sclk);
++	prog_clk(dev, 0x20, &info->unka0);
++	prog_clk(dev, 0x21, &info->vdec);
+ 
+-	if (pll->type == PLL_MEMORY) {
++	if (info->mclk.clk || info->mclk.pll) {
++		nv_wr32(dev, 0x100210, 0);
++		nv_wr32(dev, 0x1002dc, 1);
++		nv_wr32(dev, 0x004018, 0x00001000);
++		prog_pll(dev, 0x02, 0x004000, &info->mclk);
++		if (nv_rd32(dev, 0x4000) & 0x00000008)
++			nv_wr32(dev, 0x004018, 0x1000d000);
++		else
++			nv_wr32(dev, 0x004018, 0x10005000);
+ 		nv_wr32(dev, 0x1002dc, 0);
+ 		nv_wr32(dev, 0x100210, 0x80000000);
+ 	}
+ 
+-	kfree(pll);
++cleanup:
++	/* unfreeze PFIFO */
++	nv_mask(dev, 0x002504, 0x00000001, 0x00000000);
++	/* restore ctxprog to normal */
++	nv_wr32(dev, 0x400324, 0x00000000);
++	nv_wr32(dev, 0x400328, 0x0070009c); /* set flag 0x1c */
++	/* unblock it if necessary */
++	if (nv_rd32(dev, 0x400308) == 0x0050001c)
++		nv_mask(dev, 0x400824, 0x10000000, 0x10000000);
++	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
++	kfree(info);
+ }
+-
+diff --git a/drivers/gpu/drm/nouveau/nvc0_fb.c b/drivers/gpu/drm/nouveau/nvc0_fb.c
+index 08e6b11..5bf5503 100644
+--- a/drivers/gpu/drm/nouveau/nvc0_fb.c
++++ b/drivers/gpu/drm/nouveau/nvc0_fb.c
+@@ -32,6 +32,30 @@ struct nvc0_fb_priv {
+ 	dma_addr_t r100c10;
+ };
+ 
++static inline void
++nvc0_mfb_subp_isr(struct drm_device *dev, int unit, int subp)
++{
++	u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400);
++	u32 stat = nv_rd32(dev, subp_base + 0x020);
++
++	if (stat) {
++		NV_INFO(dev, "PMFB%d_SUBP%d: 0x%08x\n", unit, subp, stat);
++		nv_wr32(dev, subp_base + 0x020, stat);
++	}
++}
++
++static void
++nvc0_mfb_isr(struct drm_device *dev)
++{
++	u32 units = nv_rd32(dev, 0x00017c);
++	while (units) {
++		u32 subp, unit = ffs(units) - 1;
++		for (subp = 0; subp < 2; subp++)
++			nvc0_mfb_subp_isr(dev, unit, subp);
++		units &= ~(1 << unit);
++	}
++}
++
+ static void
+ nvc0_fb_destroy(struct drm_device *dev)
+ {
+@@ -39,6 +63,8 @@ nvc0_fb_destroy(struct drm_device *dev)
+ 	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+ 	struct nvc0_fb_priv *priv = pfb->priv;
+ 
++	nouveau_irq_unregister(dev, 25);
++
+ 	if (priv->r100c10_page) {
+ 		pci_unmap_page(dev->pdev, priv->r100c10, PAGE_SIZE,
+ 			       PCI_DMA_BIDIRECTIONAL);
+@@ -74,6 +100,7 @@ nvc0_fb_create(struct drm_device *dev)
+ 		return -EFAULT;
+ 	}
+ 
++	nouveau_irq_register(dev, 25, nvc0_mfb_isr);
+ 	return 0;
+ }
+ 
+diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
+index 6f9f341..dcbe0d5 100644
+--- a/drivers/gpu/drm/nouveau/nvc0_fifo.c
++++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c
+@@ -322,7 +322,7 @@ nvc0_fifo_init(struct drm_device *dev)
+ 	}
+ 
+ 	/* PSUBFIFO[n] */
+-	for (i = 0; i < 3; i++) {
++	for (i = 0; i < priv->spoon_nr; i++) {
+ 		nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
+ 		nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
+ 		nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */
+diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
+index 5b2f6f4..4b8d0b3 100644
+--- a/drivers/gpu/drm/nouveau/nvc0_graph.c
++++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
+@@ -390,7 +390,7 @@ nvc0_graph_init_gpc_0(struct drm_device *dev)
+ 	}
+ 
+ 	nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918);
+-	nv_wr32(dev, GPC_BCAST(0x08ac), priv->rop_nr);
++	nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800));
+ }
+ 
+ static void
+@@ -700,22 +700,6 @@ nvc0_graph_isr(struct drm_device *dev)
+ 	nv_wr32(dev, 0x400500, 0x00010001);
+ }
+ 
+-static void
+-nvc0_runk140_isr(struct drm_device *dev)
+-{
+-	u32 units = nv_rd32(dev, 0x00017c) & 0x1f;
+-
+-	while (units) {
+-		u32 unit = ffs(units) - 1;
+-		u32 reg = 0x140000 + unit * 0x2000;
+-		u32 st0 = nv_mask(dev, reg + 0x1020, 0, 0);
+-		u32 st1 = nv_mask(dev, reg + 0x1420, 0, 0);
+-
+-		NV_DEBUG(dev, "PRUNK140: %d 0x%08x 0x%08x\n", unit, st0, st1);
+-		units &= ~(1 << unit);
+-	}
+-}
+-
+ static int
+ nvc0_graph_create_fw(struct drm_device *dev, const char *fwname,
+ 		     struct nvc0_graph_fuc *fuc)
+@@ -764,7 +748,6 @@ nvc0_graph_destroy(struct drm_device *dev, int engine)
+ 	}
+ 
+ 	nouveau_irq_unregister(dev, 12);
+-	nouveau_irq_unregister(dev, 25);
+ 
+ 	nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
+ 	nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
+@@ -803,7 +786,6 @@ nvc0_graph_create(struct drm_device *dev)
+ 
+ 	NVOBJ_ENGINE_ADD(dev, GR, &priv->base);
+ 	nouveau_irq_register(dev, 12, nvc0_graph_isr);
+-	nouveau_irq_register(dev, 25, nvc0_runk140_isr);
+ 
+ 	if (nouveau_ctxfw) {
+ 		NV_INFO(dev, "PGRAPH: using external firmware\n");
+@@ -864,6 +846,9 @@ nvc0_graph_create(struct drm_device *dev)
+ 	case 0xce: /* 4/4/0/0, 4 */
+ 		priv->magic_not_rop_nr = 0x03;
+ 		break;
++	case 0xcf: /* 4/0/0/0, 3 */
++		priv->magic_not_rop_nr = 0x03;
++		break;
+ 	}
+ 
+ 	if (!priv->magic_not_rop_nr) {
+@@ -889,20 +874,3 @@ error:
+ 	nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR);
+ 	return ret;
+ }
+-
+-MODULE_FIRMWARE("nouveau/nvc0_fuc409c");
+-MODULE_FIRMWARE("nouveau/nvc0_fuc409d");
+-MODULE_FIRMWARE("nouveau/nvc0_fuc41ac");
+-MODULE_FIRMWARE("nouveau/nvc0_fuc41ad");
+-MODULE_FIRMWARE("nouveau/nvc3_fuc409c");
+-MODULE_FIRMWARE("nouveau/nvc3_fuc409d");
+-MODULE_FIRMWARE("nouveau/nvc3_fuc41ac");
+-MODULE_FIRMWARE("nouveau/nvc3_fuc41ad");
+-MODULE_FIRMWARE("nouveau/nvc4_fuc409c");
+-MODULE_FIRMWARE("nouveau/nvc4_fuc409d");
+-MODULE_FIRMWARE("nouveau/nvc4_fuc41ac");
+-MODULE_FIRMWARE("nouveau/nvc4_fuc41ad");
+-MODULE_FIRMWARE("nouveau/fuc409c");
+-MODULE_FIRMWARE("nouveau/fuc409d");
+-MODULE_FIRMWARE("nouveau/fuc41ac");
+-MODULE_FIRMWARE("nouveau/fuc41ad");
+diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.h b/drivers/gpu/drm/nouveau/nvc0_graph.h
+index 55689e9..636fe98 100644
+--- a/drivers/gpu/drm/nouveau/nvc0_graph.h
++++ b/drivers/gpu/drm/nouveau/nvc0_graph.h
+@@ -82,6 +82,7 @@ nvc0_graph_class(struct drm_device *dev)
+ 	case 0xc3:
+ 	case 0xc4:
+ 	case 0xce: /* guess, mmio trace shows only 0x9097 state */
++	case 0xcf: /* guess, mmio trace shows only 0x9097 state */
+ 		return 0x9097;
+ 	case 0xc1:
+ 		return 0x9197;
+diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c
+index 31018ea..dd0e6a7 100644
+--- a/drivers/gpu/drm/nouveau/nvc0_grctx.c
++++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c
+@@ -1678,7 +1678,10 @@ nvc0_grctx_generate_tp(struct drm_device *dev)
+ 	nv_wr32(dev, 0x419c04, 0x00000006);
+ 	nv_wr32(dev, 0x419c08, 0x00000002);
+ 	nv_wr32(dev, 0x419c20, 0x00000000);
+-	nv_wr32(dev, 0x419cb0, 0x00060048); //XXX: 0xce 0x00020048
++	if (chipset == 0xce || chipset == 0xcf)
++		nv_wr32(dev, 0x419cb0, 0x00020048);
++	else
++		nv_wr32(dev, 0x419cb0, 0x00060048);
+ 	nv_wr32(dev, 0x419ce8, 0x00000000);
+ 	nv_wr32(dev, 0x419cf4, 0x00000183);
+ 	nv_wr32(dev, 0x419d20, chipset != 0xc1 ? 0x02180000 : 0x12180000);
+@@ -1783,11 +1786,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
+ 	nv_wr32(dev, 0x40587c, 0x00000000);
+ 
+ 	if (1) {
+-		const u8 chipset_tp_max[] = { 16, 4, 0, 4, 8, 0, 0, 0,
+-					      16, 0, 0, 0, 0, 0, 8, 0 };
+-		u8 max = chipset_tp_max[dev_priv->chipset & 0x0f];
+-		u8 tpnr[GPC_MAX];
+-		u8 data[TP_MAX];
++		u8 tpnr[GPC_MAX], data[TP_MAX];
+ 
+ 		memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr));
+ 		memset(data, 0x1f, sizeof(data));
+@@ -1801,7 +1800,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
+ 			data[tp] = gpc;
+ 		}
+ 
+-		for (i = 0; i < max / 4; i++)
++		for (i = 0; i < 4; i++)
+ 			nv_wr32(dev, 0x4060a8 + (i * 4), ((u32 *)data)[i]);
+ 	}
+ 
+diff --git a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc
+index 0ec2add..06f5e26 100644
+--- a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc
++++ b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc
+@@ -77,6 +77,11 @@ chipsets:
+ .b16 nvc0_gpc_mmio_tail
+ .b16 nvc0_tpc_mmio_head
+ .b16 nvc3_tpc_mmio_tail
++.b8  0xcf 0 0 0
++.b16 nvc0_gpc_mmio_head
++.b16 nvc0_gpc_mmio_tail
++.b16 nvc0_tpc_mmio_head
++.b16 nvcf_tpc_mmio_tail
+ .b8  0 0 0 0
+ 
+ // GPC mmio lists
+@@ -134,8 +139,9 @@ mmctx_data(0x000750, 2)
+ nvc0_tpc_mmio_tail:
+ mmctx_data(0x000758, 1)
+ mmctx_data(0x0002c4, 1)
+-mmctx_data(0x0004bc, 1)
+ mmctx_data(0x0006e0, 1)
++nvcf_tpc_mmio_tail:
++mmctx_data(0x0004bc, 1)
+ nvc3_tpc_mmio_tail:
+ mmctx_data(0x000544, 1)
+ nvc1_tpc_mmio_tail:
+diff --git a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h
+index 1896c89..6f82032 100644
+--- a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h
++++ b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h
+@@ -25,23 +25,26 @@ uint32_t nvc0_grgpc_data[] = {
+ 	0x00000000,
+ 	0x00000000,
+ 	0x000000c0,
+-	0x011000b0,
+-	0x01640114,
++	0x011c00bc,
++	0x01700120,
+ 	0x000000c1,
+-	0x011400b0,
+-	0x01780114,
++	0x012000bc,
++	0x01840120,
+ 	0x000000c3,
+-	0x011000b0,
+-	0x01740114,
++	0x011c00bc,
++	0x01800120,
+ 	0x000000c4,
+-	0x011000b0,
+-	0x01740114,
++	0x011c00bc,
++	0x01800120,
+ 	0x000000c8,
+-	0x011000b0,
+-	0x01640114,
++	0x011c00bc,
++	0x01700120,
+ 	0x000000ce,
+-	0x011000b0,
+-	0x01740114,
++	0x011c00bc,
++	0x01800120,
++	0x000000cf,
++	0x011c00bc,
++	0x017c0120,
+ 	0x00000000,
+ 	0x00000380,
+ 	0x14000400,
+@@ -90,8 +93,8 @@ uint32_t nvc0_grgpc_data[] = {
+ 	0x04000750,
+ 	0x00000758,
+ 	0x000002c4,
+-	0x000004bc,
+ 	0x000006e0,
++	0x000004bc,
+ 	0x00000544,
+ };
+ 
+diff --git a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc
+index a1a5991..e4f8c7e 100644
+--- a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc
++++ b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc
+@@ -56,6 +56,9 @@ chipsets:
+ .b8  0xce 0 0 0
+ .b16 nvc0_hub_mmio_head
+ .b16 nvc0_hub_mmio_tail
++.b8  0xcf 0 0 0
++.b16 nvc0_hub_mmio_head
++.b16 nvc0_hub_mmio_tail
+ .b8  0 0 0 0
+ 
+ nvc0_hub_mmio_head:
+diff --git a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h
+index b3b541b..241d326 100644
+--- a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h
++++ b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h
+@@ -23,17 +23,19 @@ uint32_t nvc0_grhub_data[] = {
+ 	0x00000000,
+ 	0x00000000,
+ 	0x000000c0,
+-	0x012c0090,
++	0x01340098,
+ 	0x000000c1,
+-	0x01300090,
++	0x01380098,
+ 	0x000000c3,
+-	0x012c0090,
++	0x01340098,
+ 	0x000000c4,
+-	0x012c0090,
++	0x01340098,
+ 	0x000000c8,
+-	0x012c0090,
++	0x01340098,
+ 	0x000000ce,
+-	0x012c0090,
++	0x01340098,
++	0x000000cf,
++	0x01340098,
+ 	0x00000000,
+ 	0x0417e91c,
+ 	0x04400204,
+@@ -190,8 +192,6 @@ uint32_t nvc0_grhub_data[] = {
+ 	0x00000000,
+ 	0x00000000,
+ 	0x00000000,
+-	0x00000000,
+-	0x00000000,
+ };
+ 
+ uint32_t nvc0_grhub_code[] = {
+diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c
+new file mode 100644
+index 0000000..929aded
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nvc0_pm.c
+@@ -0,0 +1,155 @@
++/*
++ * Copyright 2011 Red Hat Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: Ben Skeggs
++ */
++
++#include "drmP.h"
++#include "nouveau_drv.h"
++#include "nouveau_bios.h"
++#include "nouveau_pm.h"
++
++static u32 read_div(struct drm_device *, int, u32, u32);
++static u32 read_pll(struct drm_device *, u32);
++
++static u32
++read_vco(struct drm_device *dev, u32 dsrc)
++{
++	u32 ssrc = nv_rd32(dev, dsrc);
++	if (!(ssrc & 0x00000100))
++		return read_pll(dev, 0x00e800);
++	return read_pll(dev, 0x00e820);
++}
++
++static u32
++read_pll(struct drm_device *dev, u32 pll)
++{
++	u32 ctrl = nv_rd32(dev, pll + 0);
++	u32 coef = nv_rd32(dev, pll + 4);
++	u32 P = (coef & 0x003f0000) >> 16;
++	u32 N = (coef & 0x0000ff00) >> 8;
++	u32 M = (coef & 0x000000ff) >> 0;
++	u32 sclk, doff;
++
++	if (!(ctrl & 0x00000001))
++		return 0;
++
++	switch (pll & 0xfff000) {
++	case 0x00e000:
++		sclk = 27000;
++		P = 1;
++		break;
++	case 0x137000:
++		doff = (pll - 0x137000) / 0x20;
++		sclk = read_div(dev, doff, 0x137120, 0x137140);
++		break;
++	case 0x132000:
++		switch (pll) {
++		case 0x132000:
++			sclk = read_pll(dev, 0x132020);
++			break;
++		case 0x132020:
++			sclk = read_div(dev, 0, 0x137320, 0x137330);
++			break;
++		default:
++			return 0;
++		}
++		break;
++	default:
++		return 0;
++	}
++
++	return sclk * N / M / P;
++}
++
++static u32
++read_div(struct drm_device *dev, int doff, u32 dsrc, u32 dctl)
++{
++	u32 ssrc = nv_rd32(dev, dsrc + (doff * 4));
++	u32 sctl = nv_rd32(dev, dctl + (doff * 4));
++
++	switch (ssrc & 0x00000003) {
++	case 0:
++		if ((ssrc & 0x00030000) != 0x00030000)
++			return 27000;
++		return 108000;
++	case 2:
++		return 100000;
++	case 3:
++		if (sctl & 0x80000000) {
++			u32 sclk = read_vco(dev, dsrc + (doff * 4));
++			u32 sdiv = (sctl & 0x0000003f) + 2;
++			return (sclk * 2) / sdiv;
++		}
++
++		return read_vco(dev, dsrc + (doff * 4));
++	default:
++		return 0;
++	}
++}
++
++static u32
++read_mem(struct drm_device *dev)
++{
++	u32 ssel = nv_rd32(dev, 0x1373f0);
++	if (ssel & 0x00000001)
++		return read_div(dev, 0, 0x137300, 0x137310);
++	return read_pll(dev, 0x132000);
++}
++
++static u32
++read_clk(struct drm_device *dev, int clk)
++{
++	u32 sctl = nv_rd32(dev, 0x137250 + (clk * 4));
++	u32 ssel = nv_rd32(dev, 0x137100);
++	u32 sclk, sdiv;
++
++	if (ssel & (1 << clk)) {
++		if (clk < 7)
++			sclk = read_pll(dev, 0x137000 + (clk * 0x20));
++		else
++			sclk = read_pll(dev, 0x1370e0);
++		sdiv = ((sctl & 0x00003f00) >> 8) + 2;
++	} else {
++		sclk = read_div(dev, clk, 0x137160, 0x1371d0);
++		sdiv = ((sctl & 0x0000003f) >> 0) + 2;
++	}
++
++	if (sctl & 0x80000000)
++		return (sclk * 2) / sdiv;
++	return sclk;
++}
++
++int
++nvc0_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
++{
++	perflvl->shader = read_clk(dev, 0x00);
++	perflvl->core   = perflvl->shader / 2;
++	perflvl->memory = read_mem(dev);
++	perflvl->rop    = read_clk(dev, 0x01);
++	perflvl->hub07  = read_clk(dev, 0x02);
++	perflvl->hub06  = read_clk(dev, 0x07);
++	perflvl->hub01  = read_clk(dev, 0x08);
++	perflvl->copy   = read_clk(dev, 0x09);
++	perflvl->daemon = read_clk(dev, 0x0c);
++	perflvl->vdec   = read_clk(dev, 0x0e);
++	return 0;
++}
+diff --git a/drivers/gpu/drm/nouveau/nvc0_vram.c b/drivers/gpu/drm/nouveau/nvc0_vram.c
+index e45a24d..edbfe93 100644
+--- a/drivers/gpu/drm/nouveau/nvc0_vram.c
++++ b/drivers/gpu/drm/nouveau/nvc0_vram.c
+@@ -61,7 +61,7 @@ nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin,
+ 	      u32 type, struct nouveau_mem **pmem)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_mm *mm = dev_priv->engine.vram.mm;
++	struct nouveau_mm *mm = &dev_priv->engine.vram.mm;
+ 	struct nouveau_mm_node *r;
+ 	struct nouveau_mem *mem;
+ 	int ret;
+@@ -106,12 +106,50 @@ nvc0_vram_init(struct drm_device *dev)
+ 	struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
+ 	const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+ 	const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+-	u32 length;
++	u32 parts = nv_rd32(dev, 0x121c74);
++	u32 bsize = nv_rd32(dev, 0x10f20c);
++	u32 offset, length;
++	bool uniform = true;
++	int ret, i;
+ 
+-	dev_priv->vram_size  = nv_rd32(dev, 0x10f20c) << 20;
+-	dev_priv->vram_size *= nv_rd32(dev, 0x121c74);
++	NV_DEBUG(dev, "0x100800: 0x%08x\n", nv_rd32(dev, 0x100800));
++	NV_DEBUG(dev, "parts 0x%08x bcast_mem_amount 0x%08x\n", parts, bsize);
+ 
+-	length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail;
++	/* read amount of vram attached to each memory controller */
++	for (i = 0; i < parts; i++) {
++		u32 psize = nv_rd32(dev, 0x11020c + (i * 0x1000));
++		if (psize != bsize) {
++			if (psize < bsize)
++				bsize = psize;
++			uniform = false;
++		}
++
++		NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", i, psize);
++
++		dev_priv->vram_size += (u64)psize << 20;
++	}
++
++	/* if all controllers have the same amount attached, there's no holes */
++	if (uniform) {
++		offset = rsvd_head;
++		length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail;
++		return nouveau_mm_init(&vram->mm, offset, length, 1);
++	}
+ 
+-	return nouveau_mm_init(&vram->mm, rsvd_head, length, 1);
++	/* otherwise, address lowest common amount from 0GiB */
++	ret = nouveau_mm_init(&vram->mm, rsvd_head, (bsize << 8) * parts, 1);
++	if (ret)
++		return ret;
++
++	/* and the rest starting from (8GiB + common_size) */
++	offset = (0x0200000000ULL >> 12) + (bsize << 8);
++	length = (dev_priv->vram_size >> 12) - (bsize << 8) - rsvd_tail;
++
++	ret = nouveau_mm_init(&vram->mm, offset, length, 0);
++	if (ret) {
++		nouveau_mm_fini(&vram->mm);
++		return ret;
++	}
++
++	return 0;
+ }
+diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
+new file mode 100644
+index 0000000..23d63b4
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nvd0_display.c
+@@ -0,0 +1,1473 @@
++/*
++ * Copyright 2011 Red Hat Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: Ben Skeggs
++ */
++
++#include <linux/dma-mapping.h>
++
++#include "drmP.h"
++#include "drm_crtc_helper.h"
++
++#include "nouveau_drv.h"
++#include "nouveau_connector.h"
++#include "nouveau_encoder.h"
++#include "nouveau_crtc.h"
++#include "nouveau_dma.h"
++#include "nouveau_fb.h"
++#include "nv50_display.h"
++
++struct nvd0_display {
++	struct nouveau_gpuobj *mem;
++	struct {
++		dma_addr_t handle;
++		u32 *ptr;
++	} evo[1];
++
++	struct tasklet_struct tasklet;
++	u32 modeset;
++};
++
++static struct nvd0_display *
++nvd0_display(struct drm_device *dev)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	return dev_priv->engine.display.priv;
++}
++
++static inline int
++evo_icmd(struct drm_device *dev, int id, u32 mthd, u32 data)
++{
++	int ret = 0;
++	nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000001);
++	nv_wr32(dev, 0x610704 + (id * 0x10), data);
++	nv_mask(dev, 0x610704 + (id * 0x10), 0x80000ffc, 0x80000000 | mthd);
++	if (!nv_wait(dev, 0x610704 + (id * 0x10), 0x80000000, 0x00000000))
++		ret = -EBUSY;
++	nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000000);
++	return ret;
++}
++
++static u32 *
++evo_wait(struct drm_device *dev, int id, int nr)
++{
++	struct nvd0_display *disp = nvd0_display(dev);
++	u32 put = nv_rd32(dev, 0x640000 + (id * 0x1000)) / 4;
++
++	if (put + nr >= (PAGE_SIZE / 4)) {
++		disp->evo[id].ptr[put] = 0x20000000;
++
++		nv_wr32(dev, 0x640000 + (id * 0x1000), 0x00000000);
++		if (!nv_wait(dev, 0x640004 + (id * 0x1000), ~0, 0x00000000)) {
++			NV_ERROR(dev, "evo %d dma stalled\n", id);
++			return NULL;
++		}
++
++		put = 0;
++	}
++
++	return disp->evo[id].ptr + put;
++}
++
++static void
++evo_kick(u32 *push, struct drm_device *dev, int id)
++{
++	struct nvd0_display *disp = nvd0_display(dev);
++	nv_wr32(dev, 0x640000 + (id * 0x1000), (push - disp->evo[id].ptr) << 2);
++}
++
++#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m))
++#define evo_data(p,d)   *((p)++) = (d)
++
++static struct drm_crtc *
++nvd0_display_crtc_get(struct drm_encoder *encoder)
++{
++	return nouveau_encoder(encoder)->crtc;
++}
++
++/******************************************************************************
++ * CRTC
++ *****************************************************************************/
++static int
++nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool on, bool update)
++{
++	struct drm_device *dev = nv_crtc->base.dev;
++	u32 *push, mode;
++
++	mode = 0x00000000;
++	if (on) {
++		/* 0x11: 6bpc dynamic 2x2
++		 * 0x13: 8bpc dynamic 2x2
++		 * 0x19: 6bpc static 2x2
++		 * 0x1b: 8bpc static 2x2
++		 * 0x21: 6bpc temporal
++		 * 0x23: 8bpc temporal
++		 */
++		mode = 0x00000011;
++	}
++
++	push = evo_wait(dev, 0, 4);
++	if (push) {
++		evo_mthd(push, 0x0490 + (nv_crtc->index * 0x300), 1);
++		evo_data(push, mode);
++		if (update) {
++			evo_mthd(push, 0x0080, 1);
++			evo_data(push, 0x00000000);
++		}
++		evo_kick(push, dev, 0);
++	}
++
++	return 0;
++}
++
++static int
++nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, int type, bool update)
++{
++	struct drm_display_mode *mode = &nv_crtc->base.mode;
++	struct drm_device *dev = nv_crtc->base.dev;
++	struct nouveau_connector *nv_connector;
++	u32 *push, outX, outY;
++
++	outX = mode->hdisplay;
++	outY = mode->vdisplay;
++
++	nv_connector = nouveau_crtc_connector_get(nv_crtc);
++	if (nv_connector && nv_connector->native_mode) {
++		struct drm_display_mode *native = nv_connector->native_mode;
++		u32 xratio = (native->hdisplay << 19) / mode->hdisplay;
++		u32 yratio = (native->vdisplay << 19) / mode->vdisplay;
++
++		switch (type) {
++		case DRM_MODE_SCALE_ASPECT:
++			if (xratio > yratio) {
++				outX = (mode->hdisplay * yratio) >> 19;
++				outY = (mode->vdisplay * yratio) >> 19;
++			} else {
++				outX = (mode->hdisplay * xratio) >> 19;
++				outY = (mode->vdisplay * xratio) >> 19;
++			}
++			break;
++		case DRM_MODE_SCALE_FULLSCREEN:
++			outX = native->hdisplay;
++			outY = native->vdisplay;
++			break;
++		default:
++			break;
++		}
++	}
++
++	push = evo_wait(dev, 0, 16);
++	if (push) {
++		evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
++		evo_data(push, (outY << 16) | outX);
++		evo_data(push, (outY << 16) | outX);
++		evo_data(push, (outY << 16) | outX);
++		evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1);
++		evo_data(push, 0x00000000);
++		evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1);
++		evo_data(push, (mode->vdisplay << 16) | mode->hdisplay);
++		if (update) {
++			evo_mthd(push, 0x0080, 1);
++			evo_data(push, 0x00000000);
++		}
++		evo_kick(push, dev, 0);
++	}
++
++	return 0;
++}
++
++static int
++nvd0_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb,
++		    int x, int y, bool update)
++{
++	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb);
++	u32 *push;
++
++	push = evo_wait(fb->dev, 0, 16);
++	if (push) {
++		evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1);
++		evo_data(push, nvfb->nvbo->bo.offset >> 8);
++		evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4);
++		evo_data(push, (fb->height << 16) | fb->width);
++		evo_data(push, nvfb->r_pitch);
++		evo_data(push, nvfb->r_format);
++		evo_data(push, nvfb->r_dma);
++		evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1);
++		evo_data(push, (y << 16) | x);
++		if (update) {
++			evo_mthd(push, 0x0080, 1);
++			evo_data(push, 0x00000000);
++		}
++		evo_kick(push, fb->dev, 0);
++	}
++
++	nv_crtc->fb.tile_flags = nvfb->r_dma;
++	return 0;
++}
++
++static void
++nvd0_crtc_cursor_show(struct nouveau_crtc *nv_crtc, bool show, bool update)
++{
++	struct drm_device *dev = nv_crtc->base.dev;
++	u32 *push = evo_wait(dev, 0, 16);
++	if (push) {
++		if (show) {
++			evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2);
++			evo_data(push, 0x85000000);
++			evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
++			evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
++			evo_data(push, NvEvoVRAM);
++		} else {
++			evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1);
++			evo_data(push, 0x05000000);
++			evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
++			evo_data(push, 0x00000000);
++		}
++
++		if (update) {
++			evo_mthd(push, 0x0080, 1);
++			evo_data(push, 0x00000000);
++		}
++
++		evo_kick(push, dev, 0);
++	}
++}
++
++static void
++nvd0_crtc_dpms(struct drm_crtc *crtc, int mode)
++{
++}
++
++static void
++nvd0_crtc_prepare(struct drm_crtc *crtc)
++{
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
++	u32 *push;
++
++	push = evo_wait(crtc->dev, 0, 2);
++	if (push) {
++		evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
++		evo_data(push, 0x00000000);
++		evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1);
++		evo_data(push, 0x03000000);
++		evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
++		evo_data(push, 0x00000000);
++		evo_kick(push, crtc->dev, 0);
++	}
++
++	nvd0_crtc_cursor_show(nv_crtc, false, false);
++}
++
++static void
++nvd0_crtc_commit(struct drm_crtc *crtc)
++{
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
++	u32 *push;
++
++	push = evo_wait(crtc->dev, 0, 32);
++	if (push) {
++		evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
++		evo_data(push, nv_crtc->fb.tile_flags);
++		evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4);
++		evo_data(push, 0x83000000);
++		evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
++		evo_data(push, 0x00000000);
++		evo_data(push, 0x00000000);
++		evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
++		evo_data(push, NvEvoVRAM);
++		evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1);
++		evo_data(push, 0xffffff00);
++		evo_kick(push, crtc->dev, 0);
++	}
++
++	nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true);
++}
++
++static bool
++nvd0_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
++		     struct drm_display_mode *adjusted_mode)
++{
++	return true;
++}
++
++static int
++nvd0_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
++{
++	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
++	int ret;
++
++	ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
++	if (ret)
++		return ret;
++
++	if (old_fb) {
++		nvfb = nouveau_framebuffer(old_fb);
++		nouveau_bo_unpin(nvfb->nvbo);
++	}
++
++	return 0;
++}
++
++static int
++nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
++		   struct drm_display_mode *mode, int x, int y,
++		   struct drm_framebuffer *old_fb)
++{
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
++	struct nouveau_connector *nv_connector;
++	u32 htotal = mode->htotal;
++	u32 vtotal = mode->vtotal;
++	u32 hsyncw = mode->hsync_end - mode->hsync_start - 1;
++	u32 vsyncw = mode->vsync_end - mode->vsync_start - 1;
++	u32 hfrntp = mode->hsync_start - mode->hdisplay;
++	u32 vfrntp = mode->vsync_start - mode->vdisplay;
++	u32 hbackp = mode->htotal - mode->hsync_end;
++	u32 vbackp = mode->vtotal - mode->vsync_end;
++	u32 hss2be = hsyncw + hbackp;
++	u32 vss2be = vsyncw + vbackp;
++	u32 hss2de = htotal - hfrntp;
++	u32 vss2de = vtotal - vfrntp;
++	u32 syncs, *push;
++	int ret;
++
++	syncs = 0x00000001;
++	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
++		syncs |= 0x00000008;
++	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
++		syncs |= 0x00000010;
++
++	ret = nvd0_crtc_swap_fbs(crtc, old_fb);
++	if (ret)
++		return ret;
++
++	push = evo_wait(crtc->dev, 0, 64);
++	if (push) {
++		evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 5);
++		evo_data(push, 0x00000000);
++		evo_data(push, (vtotal << 16) | htotal);
++		evo_data(push, (vsyncw << 16) | hsyncw);
++		evo_data(push, (vss2be << 16) | hss2be);
++		evo_data(push, (vss2de << 16) | hss2de);
++		evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1);
++		evo_data(push, 0x00000000); /* ??? */
++		evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3);
++		evo_data(push, mode->clock * 1000);
++		evo_data(push, 0x00200000); /* ??? */
++		evo_data(push, mode->clock * 1000);
++		evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 1);
++		evo_data(push, syncs);
++		evo_kick(push, crtc->dev, 0);
++	}
++
++	nv_connector = nouveau_crtc_connector_get(nv_crtc);
++	nvd0_crtc_set_dither(nv_crtc, nv_connector->use_dithering, false);
++	nvd0_crtc_set_scale(nv_crtc, nv_connector->scaling_mode, false);
++	nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
++	return 0;
++}
++
++static int
++nvd0_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
++			struct drm_framebuffer *old_fb)
++{
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
++	int ret;
++
++	if (!crtc->fb) {
++		NV_DEBUG_KMS(crtc->dev, "No FB bound\n");
++		return 0;
++	}
++
++	ret = nvd0_crtc_swap_fbs(crtc, old_fb);
++	if (ret)
++		return ret;
++
++	nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
++	return 0;
++}
++
++static int
++nvd0_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
++			       struct drm_framebuffer *fb, int x, int y,
++			       enum mode_set_atomic state)
++{
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
++	nvd0_crtc_set_image(nv_crtc, fb, x, y, true);
++	return 0;
++}
++
++static void
++nvd0_crtc_lut_load(struct drm_crtc *crtc)
++{
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
++	void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
++	int i;
++
++	for (i = 0; i < 256; i++) {
++		writew(0x6000 + (nv_crtc->lut.r[i] >> 2), lut + (i * 0x20) + 0);
++		writew(0x6000 + (nv_crtc->lut.g[i] >> 2), lut + (i * 0x20) + 2);
++		writew(0x6000 + (nv_crtc->lut.b[i] >> 2), lut + (i * 0x20) + 4);
++	}
++}
++
++static int
++nvd0_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
++		     uint32_t handle, uint32_t width, uint32_t height)
++{
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
++	struct drm_device *dev = crtc->dev;
++	struct drm_gem_object *gem;
++	struct nouveau_bo *nvbo;
++	bool visible = (handle != 0);
++	int i, ret = 0;
++
++	if (visible) {
++		if (width != 64 || height != 64)
++			return -EINVAL;
++
++		gem = drm_gem_object_lookup(dev, file_priv, handle);
++		if (unlikely(!gem))
++			return -ENOENT;
++		nvbo = nouveau_gem_object(gem);
++
++		ret = nouveau_bo_map(nvbo);
++		if (ret == 0) {
++			for (i = 0; i < 64 * 64; i++) {
++				u32 v = nouveau_bo_rd32(nvbo, i);
++				nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v);
++			}
++			nouveau_bo_unmap(nvbo);
++		}
++
++		drm_gem_object_unreference_unlocked(gem);
++	}
++
++	if (visible != nv_crtc->cursor.visible) {
++		nvd0_crtc_cursor_show(nv_crtc, visible, true);
++		nv_crtc->cursor.visible = visible;
++	}
++
++	return ret;
++}
++
++static int
++nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
++{
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
++	const u32 data = (y << 16) | x;
++
++	nv_wr32(crtc->dev, 0x64d084 + (nv_crtc->index * 0x1000), data);
++	nv_wr32(crtc->dev, 0x64d080 + (nv_crtc->index * 0x1000), 0x00000000);
++	return 0;
++}
++
++static void
++nvd0_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
++		    uint32_t start, uint32_t size)
++{
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
++	u32 end = max(start + size, (u32)256);
++	u32 i;
++
++	for (i = start; i < end; i++) {
++		nv_crtc->lut.r[i] = r[i];
++		nv_crtc->lut.g[i] = g[i];
++		nv_crtc->lut.b[i] = b[i];
++	}
++
++	nvd0_crtc_lut_load(crtc);
++}
++
++static void
++nvd0_crtc_destroy(struct drm_crtc *crtc)
++{
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
++	nouveau_bo_unmap(nv_crtc->cursor.nvbo);
++	nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
++	nouveau_bo_unmap(nv_crtc->lut.nvbo);
++	nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
++	drm_crtc_cleanup(crtc);
++	kfree(crtc);
++}
++
++static const struct drm_crtc_helper_funcs nvd0_crtc_hfunc = {
++	.dpms = nvd0_crtc_dpms,
++	.prepare = nvd0_crtc_prepare,
++	.commit = nvd0_crtc_commit,
++	.mode_fixup = nvd0_crtc_mode_fixup,
++	.mode_set = nvd0_crtc_mode_set,
++	.mode_set_base = nvd0_crtc_mode_set_base,
++	.mode_set_base_atomic = nvd0_crtc_mode_set_base_atomic,
++	.load_lut = nvd0_crtc_lut_load,
++};
++
++static const struct drm_crtc_funcs nvd0_crtc_func = {
++	.cursor_set = nvd0_crtc_cursor_set,
++	.cursor_move = nvd0_crtc_cursor_move,
++	.gamma_set = nvd0_crtc_gamma_set,
++	.set_config = drm_crtc_helper_set_config,
++	.destroy = nvd0_crtc_destroy,
++};
++
++static void
++nvd0_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
++{
++}
++
++static void
++nvd0_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
++{
++}
++
++static int
++nvd0_crtc_create(struct drm_device *dev, int index)
++{
++	struct nouveau_crtc *nv_crtc;
++	struct drm_crtc *crtc;
++	int ret, i;
++
++	nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
++	if (!nv_crtc)
++		return -ENOMEM;
++
++	nv_crtc->index = index;
++	nv_crtc->set_dither = nvd0_crtc_set_dither;
++	nv_crtc->set_scale = nvd0_crtc_set_scale;
++	nv_crtc->cursor.set_offset = nvd0_cursor_set_offset;
++	nv_crtc->cursor.set_pos = nvd0_cursor_set_pos;
++	for (i = 0; i < 256; i++) {
++		nv_crtc->lut.r[i] = i << 8;
++		nv_crtc->lut.g[i] = i << 8;
++		nv_crtc->lut.b[i] = i << 8;
++	}
++
++	crtc = &nv_crtc->base;
++	drm_crtc_init(dev, crtc, &nvd0_crtc_func);
++	drm_crtc_helper_add(crtc, &nvd0_crtc_hfunc);
++	drm_mode_crtc_set_gamma_size(crtc, 256);
++
++	ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
++			     0, 0x0000, &nv_crtc->cursor.nvbo);
++	if (!ret) {
++		ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
++		if (!ret)
++			ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
++		if (ret)
++			nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
++	}
++
++	if (ret)
++		goto out;
++
++	ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
++			     0, 0x0000, &nv_crtc->lut.nvbo);
++	if (!ret) {
++		ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM);
++		if (!ret)
++			ret = nouveau_bo_map(nv_crtc->lut.nvbo);
++		if (ret)
++			nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
++	}
++
++	if (ret)
++		goto out;
++
++	nvd0_crtc_lut_load(crtc);
++
++out:
++	if (ret)
++		nvd0_crtc_destroy(crtc);
++	return ret;
++}
++
++/******************************************************************************
++ * DAC
++ *****************************************************************************/
++static void
++nvd0_dac_dpms(struct drm_encoder *encoder, int mode)
++{
++	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++	struct drm_device *dev = encoder->dev;
++	int or = nv_encoder->or;
++	u32 dpms_ctrl;
++
++	dpms_ctrl = 0x80000000;
++	if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF)
++		dpms_ctrl |= 0x00000001;
++	if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF)
++		dpms_ctrl |= 0x00000004;
++
++	nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
++	nv_mask(dev, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl);
++	nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
++}
++
++static bool
++nvd0_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
++		    struct drm_display_mode *adjusted_mode)
++{
++	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++	struct nouveau_connector *nv_connector;
++
++	nv_connector = nouveau_encoder_connector_get(nv_encoder);
++	if (nv_connector && nv_connector->native_mode) {
++		if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
++			int id = adjusted_mode->base.id;
++			*adjusted_mode = *nv_connector->native_mode;
++			adjusted_mode->base.id = id;
++		}
++	}
++
++	return true;
++}
++
++static void
++nvd0_dac_prepare(struct drm_encoder *encoder)
++{
++}
++
++static void
++nvd0_dac_commit(struct drm_encoder *encoder)
++{
++}
++
++static void
++nvd0_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
++		  struct drm_display_mode *adjusted_mode)
++{
++	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
++	u32 *push;
++
++	nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON);
++
++	push = evo_wait(encoder->dev, 0, 4);
++	if (push) {
++		evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 2);
++		evo_data(push, 1 << nv_crtc->index);
++		evo_data(push, 0x00ff);
++		evo_kick(push, encoder->dev, 0);
++	}
++
++	nv_encoder->crtc = encoder->crtc;
++}
++
++static void
++nvd0_dac_disconnect(struct drm_encoder *encoder)
++{
++	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++	struct drm_device *dev = encoder->dev;
++	u32 *push;
++
++	if (nv_encoder->crtc) {
++		nvd0_crtc_prepare(nv_encoder->crtc);
++
++		push = evo_wait(dev, 0, 4);
++		if (push) {
++			evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 1);
++			evo_data(push, 0x00000000);
++			evo_mthd(push, 0x0080, 1);
++			evo_data(push, 0x00000000);
++			evo_kick(push, dev, 0);
++		}
++
++		nv_encoder->crtc = NULL;
++	}
++}
++
++static enum drm_connector_status
++nvd0_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
++{
++	enum drm_connector_status status = connector_status_disconnected;
++	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++	struct drm_device *dev = encoder->dev;
++	int or = nv_encoder->or;
++	u32 load;
++
++	nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00100000);
++	udelay(9500);
++	nv_wr32(dev, 0x61a00c + (or * 0x800), 0x80000000);
++
++	load = nv_rd32(dev, 0x61a00c + (or * 0x800));
++	if ((load & 0x38000000) == 0x38000000)
++		status = connector_status_connected;
++
++	nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00000000);
++	return status;
++}
++
++static void
++nvd0_dac_destroy(struct drm_encoder *encoder)
++{
++	drm_encoder_cleanup(encoder);
++	kfree(encoder);
++}
++
++static const struct drm_encoder_helper_funcs nvd0_dac_hfunc = {
++	.dpms = nvd0_dac_dpms,
++	.mode_fixup = nvd0_dac_mode_fixup,
++	.prepare = nvd0_dac_prepare,
++	.commit = nvd0_dac_commit,
++	.mode_set = nvd0_dac_mode_set,
++	.disable = nvd0_dac_disconnect,
++	.get_crtc = nvd0_display_crtc_get,
++	.detect = nvd0_dac_detect
++};
++
++static const struct drm_encoder_funcs nvd0_dac_func = {
++	.destroy = nvd0_dac_destroy,
++};
++
++static int
++nvd0_dac_create(struct drm_connector *connector, struct dcb_entry *dcbe)
++{
++	struct drm_device *dev = connector->dev;
++	struct nouveau_encoder *nv_encoder;
++	struct drm_encoder *encoder;
++
++	nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
++	if (!nv_encoder)
++		return -ENOMEM;
++	nv_encoder->dcb = dcbe;
++	nv_encoder->or = ffs(dcbe->or) - 1;
++
++	encoder = to_drm_encoder(nv_encoder);
++	encoder->possible_crtcs = dcbe->heads;
++	encoder->possible_clones = 0;
++	drm_encoder_init(dev, encoder, &nvd0_dac_func, DRM_MODE_ENCODER_DAC);
++	drm_encoder_helper_add(encoder, &nvd0_dac_hfunc);
++
++	drm_mode_connector_attach_encoder(connector, encoder);
++	return 0;
++}
++
++/******************************************************************************
++ * SOR
++ *****************************************************************************/
++static void
++nvd0_sor_dpms(struct drm_encoder *encoder, int mode)
++{
++	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++	struct drm_device *dev = encoder->dev;
++	struct drm_encoder *partner;
++	int or = nv_encoder->or;
++	u32 dpms_ctrl;
++
++	nv_encoder->last_dpms = mode;
++
++	list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
++		struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
++
++		if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
++			continue;
++
++		if (nv_partner != nv_encoder &&
++		    nv_partner->dcb->or == nv_encoder->or) {
++			if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
++				return;
++			break;
++		}
++	}
++
++	dpms_ctrl  = (mode == DRM_MODE_DPMS_ON);
++	dpms_ctrl |= 0x80000000;
++
++	nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
++	nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
++	nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
++	nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
++}
++
++static bool
++nvd0_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
++		    struct drm_display_mode *adjusted_mode)
++{
++	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++	struct nouveau_connector *nv_connector;
++
++	nv_connector = nouveau_encoder_connector_get(nv_encoder);
++	if (nv_connector && nv_connector->native_mode) {
++		if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
++			int id = adjusted_mode->base.id;
++			*adjusted_mode = *nv_connector->native_mode;
++			adjusted_mode->base.id = id;
++		}
++	}
++
++	return true;
++}
++
++static void
++nvd0_sor_prepare(struct drm_encoder *encoder)
++{
++}
++
++static void
++nvd0_sor_commit(struct drm_encoder *encoder)
++{
++}
++
++static void
++nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
++		  struct drm_display_mode *mode)
++{
++	struct drm_nouveau_private *dev_priv = encoder->dev->dev_private;
++	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++	struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
++	struct nouveau_connector *nv_connector;
++	struct nvbios *bios = &dev_priv->vbios;
++	u32 mode_ctrl = (1 << nv_crtc->index);
++	u32 *push, or_config;
++
++	nv_connector = nouveau_encoder_connector_get(nv_encoder);
++	switch (nv_encoder->dcb->type) {
++	case OUTPUT_TMDS:
++		if (nv_encoder->dcb->sorconf.link & 1) {
++			if (mode->clock < 165000)
++				mode_ctrl |= 0x00000100;
++			else
++				mode_ctrl |= 0x00000500;
++		} else {
++			mode_ctrl |= 0x00000200;
++		}
++
++		or_config = (mode_ctrl & 0x00000f00) >> 8;
++		if (mode->clock >= 165000)
++			or_config |= 0x0100;
++		break;
++	case OUTPUT_LVDS:
++		or_config = (mode_ctrl & 0x00000f00) >> 8;
++		if (bios->fp_no_ddc) {
++			if (bios->fp.dual_link)
++				or_config |= 0x0100;
++			if (bios->fp.if_is_24bit)
++				or_config |= 0x0200;
++		} else {
++			if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
++				if (((u8 *)nv_connector->edid)[121] == 2)
++					or_config |= 0x0100;
++			} else
++			if (mode->clock >= bios->fp.duallink_transition_clk) {
++				or_config |= 0x0100;
++			}
++
++			if (or_config & 0x0100) {
++				if (bios->fp.strapless_is_24bit & 2)
++					or_config |= 0x0200;
++			} else {
++				if (bios->fp.strapless_is_24bit & 1)
++					or_config |= 0x0200;
++			}
++
++			if (nv_connector->base.display_info.bpc == 8)
++				or_config |= 0x0200;
++
++		}
++		break;
++	default:
++		BUG_ON(1);
++		break;
++	}
++
++	nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON);
++
++	push = evo_wait(encoder->dev, 0, 4);
++	if (push) {
++		evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2);
++		evo_data(push, mode_ctrl);
++		evo_data(push, or_config);
++		evo_kick(push, encoder->dev, 0);
++	}
++
++	nv_encoder->crtc = encoder->crtc;
++}
++
++static void
++nvd0_sor_disconnect(struct drm_encoder *encoder)
++{
++	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++	struct drm_device *dev = encoder->dev;
++	u32 *push;
++
++	if (nv_encoder->crtc) {
++		nvd0_crtc_prepare(nv_encoder->crtc);
++
++		push = evo_wait(dev, 0, 4);
++		if (push) {
++			evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
++			evo_data(push, 0x00000000);
++			evo_mthd(push, 0x0080, 1);
++			evo_data(push, 0x00000000);
++			evo_kick(push, dev, 0);
++		}
++
++		nv_encoder->crtc = NULL;
++		nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
++	}
++}
++
++static void
++nvd0_sor_destroy(struct drm_encoder *encoder)
++{
++	drm_encoder_cleanup(encoder);
++	kfree(encoder);
++}
++
++static const struct drm_encoder_helper_funcs nvd0_sor_hfunc = {
++	.dpms = nvd0_sor_dpms,
++	.mode_fixup = nvd0_sor_mode_fixup,
++	.prepare = nvd0_sor_prepare,
++	.commit = nvd0_sor_commit,
++	.mode_set = nvd0_sor_mode_set,
++	.disable = nvd0_sor_disconnect,
++	.get_crtc = nvd0_display_crtc_get,
++};
++
++static const struct drm_encoder_funcs nvd0_sor_func = {
++	.destroy = nvd0_sor_destroy,
++};
++
++static int
++nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe)
++{
++	struct drm_device *dev = connector->dev;
++	struct nouveau_encoder *nv_encoder;
++	struct drm_encoder *encoder;
++
++	nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
++	if (!nv_encoder)
++		return -ENOMEM;
++	nv_encoder->dcb = dcbe;
++	nv_encoder->or = ffs(dcbe->or) - 1;
++	nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
++
++	encoder = to_drm_encoder(nv_encoder);
++	encoder->possible_crtcs = dcbe->heads;
++	encoder->possible_clones = 0;
++	drm_encoder_init(dev, encoder, &nvd0_sor_func, DRM_MODE_ENCODER_TMDS);
++	drm_encoder_helper_add(encoder, &nvd0_sor_hfunc);
++
++	drm_mode_connector_attach_encoder(connector, encoder);
++	return 0;
++}
++
++/******************************************************************************
++ * IRQ
++ *****************************************************************************/
++static struct dcb_entry *
++lookup_dcb(struct drm_device *dev, int id, u32 mc)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	int type, or, i;
++
++	if (id < 4) {
++		type = OUTPUT_ANALOG;
++		or   = id;
++	} else {
++		switch (mc & 0x00000f00) {
++		case 0x00000000: type = OUTPUT_LVDS; break;
++		case 0x00000100: type = OUTPUT_TMDS; break;
++		case 0x00000200: type = OUTPUT_TMDS; break;
++		case 0x00000500: type = OUTPUT_TMDS; break;
++		default:
++			NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc);
++			return NULL;
++		}
++
++		or = id - 4;
++	}
++
++	for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
++		struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
++		if (dcb->type == type && (dcb->or & (1 << or)))
++			return dcb;
++	}
++
++	NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc);
++	return NULL;
++}
++
++static void
++nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask)
++{
++	struct dcb_entry *dcb;
++	int i;
++
++	for (i = 0; mask && i < 8; i++) {
++		u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
++		if (!(mcc & (1 << crtc)))
++			continue;
++
++		dcb = lookup_dcb(dev, i, mcc);
++		if (!dcb)
++			continue;
++
++		nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc);
++	}
++
++	nv_wr32(dev, 0x6101d4, 0x00000000);
++	nv_wr32(dev, 0x6109d4, 0x00000000);
++	nv_wr32(dev, 0x6101d0, 0x80000000);
++}
++
++static void
++nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask)
++{
++	struct dcb_entry *dcb;
++	u32 or, tmp, pclk;
++	int i;
++
++	for (i = 0; mask && i < 8; i++) {
++		u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
++		if (!(mcc & (1 << crtc)))
++			continue;
++
++		dcb = lookup_dcb(dev, i, mcc);
++		if (!dcb)
++			continue;
++
++		nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc);
++	}
++
++	pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
++	if (mask & 0x00010000) {
++		nv50_crtc_set_clock(dev, crtc, pclk);
++	}
++
++	for (i = 0; mask && i < 8; i++) {
++		u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
++		u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
++		if (!(mcp & (1 << crtc)))
++			continue;
++
++		dcb = lookup_dcb(dev, i, mcp);
++		if (!dcb)
++			continue;
++		or = ffs(dcb->or) - 1;
++
++		nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc);
++
++		nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000);
++		switch (dcb->type) {
++		case OUTPUT_ANALOG:
++			nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000);
++			break;
++		case OUTPUT_TMDS:
++		case OUTPUT_LVDS:
++			if (cfg & 0x00000100)
++				tmp = 0x00000101;
++			else
++				tmp = 0x00000000;
++
++			nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp);
++			break;
++		default:
++			break;
++		}
++
++		break;
++	}
++
++	nv_wr32(dev, 0x6101d4, 0x00000000);
++	nv_wr32(dev, 0x6109d4, 0x00000000);
++	nv_wr32(dev, 0x6101d0, 0x80000000);
++}
++
++static void
++nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask)
++{
++	struct dcb_entry *dcb;
++	int pclk, i;
++
++	pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
++
++	for (i = 0; mask && i < 8; i++) {
++		u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
++		u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
++		if (!(mcp & (1 << crtc)))
++			continue;
++
++		dcb = lookup_dcb(dev, i, mcp);
++		if (!dcb)
++			continue;
++
++		nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc);
++	}
++
++	nv_wr32(dev, 0x6101d4, 0x00000000);
++	nv_wr32(dev, 0x6109d4, 0x00000000);
++	nv_wr32(dev, 0x6101d0, 0x80000000);
++}
++
++static void
++nvd0_display_bh(unsigned long data)
++{
++	struct drm_device *dev = (struct drm_device *)data;
++	struct nvd0_display *disp = nvd0_display(dev);
++	u32 mask, crtc;
++	int i;
++
++	if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) {
++		NV_INFO(dev, "PDISP: modeset req %d\n", disp->modeset);
++		NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n",
++			 nv_rd32(dev, 0x6101d0),
++			 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
++		for (i = 0; i < 8; i++) {
++			NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n",
++				i < 4 ? "DAC" : "SOR", i,
++				nv_rd32(dev, 0x640180 + (i * 0x20)),
++				nv_rd32(dev, 0x660180 + (i * 0x20)));
++		}
++	}
++
++	mask = nv_rd32(dev, 0x6101d4);
++	crtc = 0;
++	if (!mask) {
++		mask = nv_rd32(dev, 0x6109d4);
++		crtc = 1;
++	}
++
++	if (disp->modeset & 0x00000001)
++		nvd0_display_unk1_handler(dev, crtc, mask);
++	if (disp->modeset & 0x00000002)
++		nvd0_display_unk2_handler(dev, crtc, mask);
++	if (disp->modeset & 0x00000004)
++		nvd0_display_unk4_handler(dev, crtc, mask);
++}
++
++static void
++nvd0_display_intr(struct drm_device *dev)
++{
++	struct nvd0_display *disp = nvd0_display(dev);
++	u32 intr = nv_rd32(dev, 0x610088);
++
++	if (intr & 0x00000002) {
++		u32 stat = nv_rd32(dev, 0x61009c);
++		int chid = ffs(stat) - 1;
++		if (chid >= 0) {
++			u32 mthd = nv_rd32(dev, 0x6101f0 + (chid * 12));
++			u32 data = nv_rd32(dev, 0x6101f4 + (chid * 12));
++			u32 unkn = nv_rd32(dev, 0x6101f8 + (chid * 12));
++
++			NV_INFO(dev, "EvoCh: chid %d mthd 0x%04x data 0x%08x "
++				     "0x%08x 0x%08x\n",
++				chid, (mthd & 0x0000ffc), data, mthd, unkn);
++			nv_wr32(dev, 0x61009c, (1 << chid));
++			nv_wr32(dev, 0x6101f0 + (chid * 12), 0x90000000);
++		}
++
++		intr &= ~0x00000002;
++	}
++
++	if (intr & 0x00100000) {
++		u32 stat = nv_rd32(dev, 0x6100ac);
++
++		if (stat & 0x00000007) {
++			disp->modeset = stat;
++			tasklet_schedule(&disp->tasklet);
++
++			nv_wr32(dev, 0x6100ac, (stat & 0x00000007));
++			stat &= ~0x00000007;
++		}
++
++		if (stat) {
++			NV_INFO(dev, "PDISP: unknown intr24 0x%08x\n", stat);
++			nv_wr32(dev, 0x6100ac, stat);
++		}
++
++		intr &= ~0x00100000;
++	}
++
++	if (intr & 0x01000000) {
++		u32 stat = nv_rd32(dev, 0x6100bc);
++		nv_wr32(dev, 0x6100bc, stat);
++		intr &= ~0x01000000;
++	}
++
++	if (intr & 0x02000000) {
++		u32 stat = nv_rd32(dev, 0x6108bc);
++		nv_wr32(dev, 0x6108bc, stat);
++		intr &= ~0x02000000;
++	}
++
++	if (intr)
++		NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr);
++}
++
++/******************************************************************************
++ * Init
++ *****************************************************************************/
++static void
++nvd0_display_fini(struct drm_device *dev)
++{
++	int i;
++
++	/* fini cursors */
++	for (i = 14; i >= 13; i--) {
++		if (!(nv_rd32(dev, 0x610490 + (i * 0x10)) & 0x00000001))
++			continue;
++
++		nv_mask(dev, 0x610490 + (i * 0x10), 0x00000001, 0x00000000);
++		nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00000000);
++		nv_mask(dev, 0x610090, 1 << i, 0x00000000);
++		nv_mask(dev, 0x6100a0, 1 << i, 0x00000000);
++	}
++
++	/* fini master */
++	if (nv_rd32(dev, 0x610490) & 0x00000010) {
++		nv_mask(dev, 0x610490, 0x00000010, 0x00000000);
++		nv_mask(dev, 0x610490, 0x00000003, 0x00000000);
++		nv_wait(dev, 0x610490, 0x80000000, 0x00000000);
++		nv_mask(dev, 0x610090, 0x00000001, 0x00000000);
++		nv_mask(dev, 0x6100a0, 0x00000001, 0x00000000);
++	}
++}
++
++int
++nvd0_display_init(struct drm_device *dev)
++{
++	struct nvd0_display *disp = nvd0_display(dev);
++	u32 *push;
++	int i;
++
++	if (nv_rd32(dev, 0x6100ac) & 0x00000100) {
++		nv_wr32(dev, 0x6100ac, 0x00000100);
++		nv_mask(dev, 0x6194e8, 0x00000001, 0x00000000);
++		if (!nv_wait(dev, 0x6194e8, 0x00000002, 0x00000000)) {
++			NV_ERROR(dev, "PDISP: 0x6194e8 0x%08x\n",
++				 nv_rd32(dev, 0x6194e8));
++			return -EBUSY;
++		}
++	}
++
++	/* nfi what these are exactly, i do know that SOR_MODE_CTRL won't
++	 * work at all unless you do the SOR part below.
++	 */
++	for (i = 0; i < 3; i++) {
++		u32 dac = nv_rd32(dev, 0x61a000 + (i * 0x800));
++		nv_wr32(dev, 0x6101c0 + (i * 0x800), dac);
++	}
++
++	for (i = 0; i < 4; i++) {
++		u32 sor = nv_rd32(dev, 0x61c000 + (i * 0x800));
++		nv_wr32(dev, 0x6301c4 + (i * 0x800), sor);
++	}
++
++	for (i = 0; i < 2; i++) {
++		u32 crtc0 = nv_rd32(dev, 0x616104 + (i * 0x800));
++		u32 crtc1 = nv_rd32(dev, 0x616108 + (i * 0x800));
++		u32 crtc2 = nv_rd32(dev, 0x61610c + (i * 0x800));
++		nv_wr32(dev, 0x6101b4 + (i * 0x800), crtc0);
++		nv_wr32(dev, 0x6101b8 + (i * 0x800), crtc1);
++		nv_wr32(dev, 0x6101bc + (i * 0x800), crtc2);
++	}
++
++	/* point at our hash table / objects, enable interrupts */
++	nv_wr32(dev, 0x610010, (disp->mem->vinst >> 8) | 9);
++	nv_mask(dev, 0x6100b0, 0x00000307, 0x00000307);
++
++	/* init master */
++	nv_wr32(dev, 0x610494, (disp->evo[0].handle >> 8) | 3);
++	nv_wr32(dev, 0x610498, 0x00010000);
++	nv_wr32(dev, 0x61049c, 0x00000001);
++	nv_mask(dev, 0x610490, 0x00000010, 0x00000010);
++	nv_wr32(dev, 0x640000, 0x00000000);
++	nv_wr32(dev, 0x610490, 0x01000013);
++	if (!nv_wait(dev, 0x610490, 0x80000000, 0x00000000)) {
++		NV_ERROR(dev, "PDISP: master 0x%08x\n",
++			 nv_rd32(dev, 0x610490));
++		return -EBUSY;
++	}
++	nv_mask(dev, 0x610090, 0x00000001, 0x00000001);
++	nv_mask(dev, 0x6100a0, 0x00000001, 0x00000001);
++
++	/* init cursors */
++	for (i = 13; i <= 14; i++) {
++		nv_wr32(dev, 0x610490 + (i * 0x10), 0x00000001);
++		if (!nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00010000)) {
++			NV_ERROR(dev, "PDISP: curs%d 0x%08x\n", i,
++				 nv_rd32(dev, 0x610490 + (i * 0x10)));
++			return -EBUSY;
++		}
++
++		nv_mask(dev, 0x610090, 1 << i, 1 << i);
++		nv_mask(dev, 0x6100a0, 1 << i, 1 << i);
++	}
++
++	push = evo_wait(dev, 0, 32);
++	if (!push)
++		return -EBUSY;
++	evo_mthd(push, 0x0088, 1);
++	evo_data(push, NvEvoSync);
++	evo_mthd(push, 0x0084, 1);
++	evo_data(push, 0x00000000);
++	evo_mthd(push, 0x0084, 1);
++	evo_data(push, 0x80000000);
++	evo_mthd(push, 0x008c, 1);
++	evo_data(push, 0x00000000);
++	evo_kick(push, dev, 0);
++
++	return 0;
++}
++
++void
++nvd0_display_destroy(struct drm_device *dev)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nvd0_display *disp = nvd0_display(dev);
++	struct pci_dev *pdev = dev->pdev;
++
++	nvd0_display_fini(dev);
++
++	pci_free_consistent(pdev, PAGE_SIZE, disp->evo[0].ptr, disp->evo[0].handle);
++	nouveau_gpuobj_ref(NULL, &disp->mem);
++	nouveau_irq_unregister(dev, 26);
++
++	dev_priv->engine.display.priv = NULL;
++	kfree(disp);
++}
++
++int
++nvd0_display_create(struct drm_device *dev)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
++	struct dcb_table *dcb = &dev_priv->vbios.dcb;
++	struct drm_connector *connector, *tmp;
++	struct pci_dev *pdev = dev->pdev;
++	struct nvd0_display *disp;
++	struct dcb_entry *dcbe;
++	int ret, i;
++
++	disp = kzalloc(sizeof(*disp), GFP_KERNEL);
++	if (!disp)
++		return -ENOMEM;
++	dev_priv->engine.display.priv = disp;
++
++	/* create crtc objects to represent the hw heads */
++	for (i = 0; i < 2; i++) {
++		ret = nvd0_crtc_create(dev, i);
++		if (ret)
++			goto out;
++	}
++
++	/* create encoder/connector objects based on VBIOS DCB table */
++	for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
++		connector = nouveau_connector_create(dev, dcbe->connector);
++		if (IS_ERR(connector))
++			continue;
++
++		if (dcbe->location != DCB_LOC_ON_CHIP) {
++			NV_WARN(dev, "skipping off-chip encoder %d/%d\n",
++				dcbe->type, ffs(dcbe->or) - 1);
++			continue;
++		}
++
++		switch (dcbe->type) {
++		case OUTPUT_TMDS:
++		case OUTPUT_LVDS:
++			nvd0_sor_create(connector, dcbe);
++			break;
++		case OUTPUT_ANALOG:
++			nvd0_dac_create(connector, dcbe);
++			break;
++		default:
++			NV_WARN(dev, "skipping unsupported encoder %d/%d\n",
++				dcbe->type, ffs(dcbe->or) - 1);
++			continue;
++		}
++	}
++
++	/* cull any connectors we created that don't have an encoder */
++	list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
++		if (connector->encoder_ids[0])
++			continue;
++
++		NV_WARN(dev, "%s has no encoders, removing\n",
++			drm_get_connector_name(connector));
++		connector->funcs->destroy(connector);
++	}
++
++	/* setup interrupt handling */
++	tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev);
++	nouveau_irq_register(dev, 26, nvd0_display_intr);
++
++	/* hash table and dma objects for the memory areas we care about */
++	ret = nouveau_gpuobj_new(dev, NULL, 0x4000, 0x10000,
++				 NVOBJ_FLAG_ZERO_ALLOC, &disp->mem);
++	if (ret)
++		goto out;
++
++	nv_wo32(disp->mem, 0x1000, 0x00000049);
++	nv_wo32(disp->mem, 0x1004, (disp->mem->vinst + 0x2000) >> 8);
++	nv_wo32(disp->mem, 0x1008, (disp->mem->vinst + 0x2fff) >> 8);
++	nv_wo32(disp->mem, 0x100c, 0x00000000);
++	nv_wo32(disp->mem, 0x1010, 0x00000000);
++	nv_wo32(disp->mem, 0x1014, 0x00000000);
++	nv_wo32(disp->mem, 0x0000, NvEvoSync);
++	nv_wo32(disp->mem, 0x0004, (0x1000 << 9) | 0x00000001);
++
++	nv_wo32(disp->mem, 0x1020, 0x00000049);
++	nv_wo32(disp->mem, 0x1024, 0x00000000);
++	nv_wo32(disp->mem, 0x1028, (dev_priv->vram_size - 1) >> 8);
++	nv_wo32(disp->mem, 0x102c, 0x00000000);
++	nv_wo32(disp->mem, 0x1030, 0x00000000);
++	nv_wo32(disp->mem, 0x1034, 0x00000000);
++	nv_wo32(disp->mem, 0x0008, NvEvoVRAM);
++	nv_wo32(disp->mem, 0x000c, (0x1020 << 9) | 0x00000001);
++
++	nv_wo32(disp->mem, 0x1040, 0x00000009);
++	nv_wo32(disp->mem, 0x1044, 0x00000000);
++	nv_wo32(disp->mem, 0x1048, (dev_priv->vram_size - 1) >> 8);
++	nv_wo32(disp->mem, 0x104c, 0x00000000);
++	nv_wo32(disp->mem, 0x1050, 0x00000000);
++	nv_wo32(disp->mem, 0x1054, 0x00000000);
++	nv_wo32(disp->mem, 0x0010, NvEvoVRAM_LP);
++	nv_wo32(disp->mem, 0x0014, (0x1040 << 9) | 0x00000001);
++
++	nv_wo32(disp->mem, 0x1060, 0x0fe00009);
++	nv_wo32(disp->mem, 0x1064, 0x00000000);
++	nv_wo32(disp->mem, 0x1068, (dev_priv->vram_size - 1) >> 8);
++	nv_wo32(disp->mem, 0x106c, 0x00000000);
++	nv_wo32(disp->mem, 0x1070, 0x00000000);
++	nv_wo32(disp->mem, 0x1074, 0x00000000);
++	nv_wo32(disp->mem, 0x0018, NvEvoFB32);
++	nv_wo32(disp->mem, 0x001c, (0x1060 << 9) | 0x00000001);
++
++	pinstmem->flush(dev);
++
++	/* push buffers for evo channels */
++	disp->evo[0].ptr =
++		pci_alloc_consistent(pdev, PAGE_SIZE, &disp->evo[0].handle);
++	if (!disp->evo[0].ptr) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	ret = nvd0_display_init(dev);
++	if (ret)
++		goto out;
++
++out:
++	if (ret)
++		nvd0_display_destroy(dev);
++	return ret;
++}
diff --git a/efi-dont-map-boot-services-on-32bit.patch b/efi-dont-map-boot-services-on-32bit.patch
new file mode 100644
index 0000000..7cc6149
--- /dev/null
+++ b/efi-dont-map-boot-services-on-32bit.patch
@@ -0,0 +1,22 @@
+diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
+index 3ae4128..ff7dc70 100644
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -659,10 +659,13 @@ void __init efi_enter_virtual_mode(void)
+ 
+ 	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ 		md = p;
+-		if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
+-		    md->type != EFI_BOOT_SERVICES_CODE &&
+-		    md->type != EFI_BOOT_SERVICES_DATA)
+-			continue;
++		if (!(md->attribute & EFI_MEMORY_RUNTIME)) {
++#ifdef CONFIG_X86_64
++			if (md->type != EFI_BOOT_SERVICES_CODE &&
++			    md->type != EFI_BOOT_SERVICES_DATA)
++#endif
++				continue;
++		}
+ 
+ 		size = md->num_pages << EFI_PAGE_SHIFT;
+ 		end = md->phys_addr + size;
diff --git a/epoll-fix-spurious-lockdep-warnings.patch b/epoll-fix-spurious-lockdep-warnings.patch
index 131796a..c163a86 100644
--- a/epoll-fix-spurious-lockdep-warnings.patch
+++ b/epoll-fix-spurious-lockdep-warnings.patch
@@ -113,4 +113,4 @@ index f9cfd16..0cb7bc6 100644
 --
 To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
 the body of a message to majordomo at vger.kernel.org
-More majordomo info at  http://vger.kernel.org/majordomo-info.html
\ No newline at end of file
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff --git a/hvcs_pi_buf_alloc.patch b/hvcs_pi_buf_alloc.patch
new file mode 100644
index 0000000..ecabe49
--- /dev/null
+++ b/hvcs_pi_buf_alloc.patch
@@ -0,0 +1,43 @@
+
+The Power platform requires the partner info buffer to be page aligned
+otherwise it will fail the partner info hcall with H_PARAMETER. Switch
+from using kmalloc to allocate this buffer to __get_free_page to ensure
+page alignment.
+
+Signed-off-by: Brian King <brking at linux.vnet.ibm.com>
+---
+
+ drivers/tty/hvc/hvcs.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff -puN drivers/tty/hvc/hvcs.c~hvcs_pi_buf_alloc drivers/tty/hvc/hvcs.c
+--- linux-2.6/drivers/tty/hvc/hvcs.c~hvcs_pi_buf_alloc	2011-09-09 16:00:25.000000000 -0500
++++ linux-2.6-bjking1/drivers/tty/hvc/hvcs.c	2011-09-09 16:07:08.000000000 -0500
+@@ -1532,7 +1532,7 @@ static int __devinit hvcs_initialize(voi
+ 		goto register_fail;
+ 	}
+ 
+-	hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL);
++	hvcs_pi_buff = (unsigned long *) __get_free_page(GFP_KERNEL);
+ 	if (!hvcs_pi_buff) {
+ 		rc = -ENOMEM;
+ 		goto buff_alloc_fail;
+@@ -1548,7 +1548,7 @@ static int __devinit hvcs_initialize(voi
+ 	return 0;
+ 
+ kthread_fail:
+-	kfree(hvcs_pi_buff);
++	free_page((unsigned long)hvcs_pi_buff);
+ buff_alloc_fail:
+ 	tty_unregister_driver(hvcs_tty_driver);
+ register_fail:
+@@ -1597,7 +1597,7 @@ static void __exit hvcs_module_exit(void
+ 	kthread_stop(hvcs_task);
+ 
+ 	spin_lock(&hvcs_pi_lock);
+-	kfree(hvcs_pi_buff);
++	free_page((unsigned long)hvcs_pi_buff);
+ 	hvcs_pi_buff = NULL;
+ 	spin_unlock(&hvcs_pi_lock);
+ 
+_
diff --git a/ideapad-Check-if-acpi-already-handle-backlight.patch b/ideapad-Check-if-acpi-already-handle-backlight.patch
new file mode 100644
index 0000000..713e005
--- /dev/null
+++ b/ideapad-Check-if-acpi-already-handle-backlight.patch
@@ -0,0 +1,31 @@
+From d4afc7754a60b885b63ef23fd194984e2d53a4e6 Mon Sep 17 00:00:00 2001
+From: Rene Bollford <xsecute at googlemail.com>
+Date: Sun, 23 Oct 2011 09:56:42 +0200
+Subject: [PATCH] [PATCH] ideapad: Check if acpi already handle backlight
+ power to avoid a page fault
+
+This patch avoid a page fault in the ideapad-laptop extras when
+turning the backlight power on or off.
+
+Signed-off-by: Rene Bolldorf <xsecute at googlemail.com>
+Signed-off-by: Matthew Garrett <mjg at redhat.com>
+---
+ drivers/platform/x86/ideapad-laptop.c |    2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
+index 0c59541..0d94eec 100644
+--- a/drivers/platform/x86/ideapad-laptop.c
++++ b/drivers/platform/x86/ideapad-laptop.c
+@@ -493,6 +493,8 @@ static void ideapad_backlight_notify_power(struct ideapad_private *priv)
+ 	unsigned long power;
+ 	struct backlight_device *blightdev = priv->blightdev;
+ 
++	if (!blightdev)
++		return;
+ 	if (read_ec_data(ideapad_handle, 0x18, &power))
+ 		return;
+ 	blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
+-- 
+1.7.6.4
+
diff --git a/iwlagn-fix-ht_params-NULL-pointer-dereference.patch b/iwlagn-fix-ht_params-NULL-pointer-dereference.patch
new file mode 100644
index 0000000..4dcf490
--- /dev/null
+++ b/iwlagn-fix-ht_params-NULL-pointer-dereference.patch
@@ -0,0 +1,43 @@
+This fix regression introduced by commit:
+
+commit 15b3f3b006b42a678523cad989bfd60b76bf4403
+Author: Wey-Yi Guy <wey-yi.w.guy at intel.com>
+Date:   Fri Jun 3 07:54:13 2011 -0700
+
+    iwlagn: set smps mode after assoc for 1000 device
+
+Also remove unneeded brackets on the way.
+
+Address:
+https://bugzilla.redhat.com/show_bug.cgi?id=744155
+
+If fix will not get 3.1 release, it should be applied in 3.1 stable.
+
+Cc: stable at kernel.org # 3.1+
+Signed-off-by: Stanislaw Gruszka <sgruszka at redhat.com>
+---
+ drivers/net/wireless/iwlwifi/iwl-agn-rxon.c |    4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+index ca632f9..5004342 100644
+--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
++++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+@@ -296,8 +296,8 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv,
+ 		return ret;
+ 	}
+ 
+-	if ((ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) &&
+-	    priv->cfg->ht_params->smps_mode)
++	if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
++	    priv->cfg->ht_params && priv->cfg->ht_params->smps_mode)
+ 		ieee80211_request_smps(ctx->vif,
+ 				       priv->cfg->ht_params->smps_mode);
+ 
+-- 
+1.7.1
+
+--
+To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
+the body of a message to majordomo at vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
\ No newline at end of file
diff --git a/kernel.spec b/kernel.spec
index 3b1cd23..a96c368 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -42,16 +42,16 @@ Summary: The Linux kernel
 # When changing real_sublevel below, reset this by hand to 1
 # (or to 0 and then use rpmdev-bumpspec).
 #
-%global baserelease 6
+%global baserelease 0
 %global fedora_build %{baserelease}
 
 # real_sublevel is the 3.x kernel version we're starting with
-%define real_sublevel 0
+%define real_sublevel 1
 # fake_sublevel is the 2.6.x version we're faking
 %define fake_sublevel %(echo $((40 + %{real_sublevel})))
 
 # Do we have a -stable update to apply?
-%define stable_update 8
+%define stable_update 0
 # Is it a -stable RC?
 %define stable_rc 0
 # Set rpm version accordingly
@@ -328,20 +328,6 @@ Summary: The Linux kernel
 %define kernel_image_elf 1
 %endif
 
-%ifarch ia64
-%define all_arch_configs kernel-%{version}-ia64*.config
-%define image_install_path boot/efi/EFI/redhat
-%define make_target compressed
-%define kernel_image vmlinux.gz
-%endif
-
-%ifarch alpha alphaev56
-%define all_arch_configs kernel-%{version}-alpha*.config
-%define image_install_path boot
-%define make_target vmlinux
-%define kernel_image vmlinux
-%endif
-
 %ifarch %{arm}
 %define all_arch_configs kernel-%{version}-arm*.config
 %define image_install_path boot
@@ -424,7 +410,7 @@ Summary: The Linux kernel
 # Packages that need to be installed before the kernel is, because the %%post
 # scripts use them.
 #
-%define kernel_prereq  fileutils, module-init-tools >= 3.16-2, initscripts >= 8.11.1-1, grubby >= 7.0.10-1
+%define kernel_prereq  fileutils, module-init-tools >= 3.16-2, initscripts >= 8.11.1-1, grubby >= 7.0.16-5
 %define initrd_prereq  dracut >= 001-7
 
 #
@@ -517,6 +503,7 @@ Source24: config-rhel-generic
 
 Source30: config-x86-generic
 Source31: config-i686-PAE
+Source32: config-x86-32-generic
 
 Source40: config-x86_64-generic
 
@@ -525,8 +512,6 @@ Source51: config-powerpc32-generic
 Source52: config-powerpc32-smp
 Source53: config-powerpc64
 
-Source60: config-ia64-generic
-
 Source70: config-s390x
 
 Source90: config-sparc64-generic
@@ -564,26 +549,23 @@ Patch05: linux-2.6-makefile-after_link.patch
 
 %if !%{nopatches}
 
+
 # revert upstream patches we get via other methods
 Patch09: linux-2.6-upstream-reverts.patch
+# Git trees.
 
 # Standalone patches
 
-Patch100: perf-check-ownership.patch
-
-Patch150: linux-2.6.29-sparc-IOC_TYPECHECK.patch
-
+Patch100: taint-vbox.patch
 Patch160: linux-2.6-32bit-mmap-exec-randomization.patch
 Patch161: linux-2.6-i386-nx-emulation.patch
 
 Patch202: linux-2.6-debug-taint-vm.patch
-Patch203: linux-2.6-debug-vm-would-have-oomkilled.patch
 
 Patch383: linux-2.6-defaults-aspm.patch
 
 Patch390: linux-2.6-defaults-acpi-video.patch
 Patch391: linux-2.6-acpi-video-dos.patch
-Patch393: acpi-ec-add-delay-before-write.patch
 Patch394: linux-2.6-acpi-debug-infinite-loop.patch
 Patch395: acpi-ensure-thermal-limits-match-cpu-freq.patch
 Patch396: acpi-sony-nonvs-blacklist.patch
@@ -598,10 +580,6 @@ Patch471: floppy-drop-disable_hlt-warning.patch
 
 Patch510: linux-2.6-silence-noise.patch
 Patch530: linux-2.6-silence-fbcon-logo.patch
-# from 3.1
-Patch540: x86-pci-reduce-severity-of-host-bridge-window-conflict-warnings.patch
-
-Patch610: hda_intel-prealloc-4mb-dmabuffer.patch
 
 Patch700: linux-2.6-e1000-ich9-montevina.patch
 
@@ -620,6 +598,8 @@ Patch1810: drm-nouveau-updates.patch
 Patch1824: drm-intel-next.patch
 # make sure the lvds comes back on lid open
 Patch1825: drm-intel-make-lvds-work.patch
+# hush the i915 fbc noise
+Patch1826: drm-i915-fbc-stfu.patch
 # rhbz#729882, https://bugs.freedesktop.org/attachment.cgi?id=49069
 Patch1827: drm-i915-sdvo-lvds-is-digital.patch
 
@@ -627,8 +607,6 @@ Patch1850: drm-lower-severity-radeon-lockup.diff
 
 Patch1900: linux-2.6-intel-iommu-igfx.patch
 
-Patch2000: block-stray-block-put-after-teardown.patch
-
 # Quiet boot fixes
 # silence the ACPI blacklist code
 Patch2802: linux-2.6-silence-acpi-blacklist.patch
@@ -638,9 +616,9 @@ Patch2899: linux-2.6-v4l-dvb-fixes.patch
 Patch2900: linux-2.6-v4l-dvb-update.patch
 Patch2901: linux-2.6-v4l-dvb-experimental.patch
 
-Patch2902: media-DiBcom-protect-the-I2C-bufer-access.patch
-Patch2903: media-dib0700-protect-the-dib0700-buffer-access.patch
-Patch2904: media-dib0700-correct-error-message.patch
+Patch2903: media-DiBcom-protect-the-I2C-bufer-access.patch
+Patch2904: media-dib0700-protect-the-dib0700-buffer-access.patch
+Patch2905: media-dib0700-correct-error-message.patch
 
 Patch3000: rcutree-avoid-false-quiescent-states.patch
 
@@ -653,21 +631,28 @@ Patch12010: add-appleir-usb-driver.patch
 
 Patch12016: disable-i8042-check-on-apple-mac.patch
 
-Patch12023: ums-realtek-driver-uses-stack-memory-for-DMA.patch
-Patch12024: usb-add-quirk-for-logitech-webcams.patch
-Patch12025: crypto-register-cryptd-first.patch
-Patch12028: x86-p4-make-watchdog-and-perf-work-together.patch
+Patch12021: udlfb-bind-framebuffer-to-interface.patch
 
-# Runtime power management
-Patch12203: linux-2.6-usb-pci-autosuspend.patch
-Patch12204: linux-2.6-enable-more-pci-autosuspend.patch
+Patch12023: ums-realtek-driver-uses-stack-memory-for-DMA.patch
+Patch12024: epoll-fix-spurious-lockdep-warnings.patch
+Patch12025: rcu-avoid-just-onlined-cpu-resched.patch
+Patch12026: block-stray-block-put-after-teardown.patch
+Patch12027: usb-add-quirk-for-logitech-webcams.patch
+Patch12029: crypto-register-cryptd-first.patch
+Patch12030: epoll-limit-paths.patch
 
 Patch12303: dmar-disable-when-ricoh-multifunction.patch
 
-Patch13001: epoll-fix-spurious-lockdep-warnings.patch
-Patch13002: epoll-limit-paths.patch
+Patch13002: revert-efi-rtclock.patch
+Patch13003: efi-dont-map-boot-services-on-32bit.patch
 
-Patch13010: iwlagn-check-for-priv--txq-in-iwlagn_wait_tx_queue_empty.patch
+Patch13007: add-macbookair41-keyboard.patch
+
+Patch13009: hvcs_pi_buf_alloc.patch
+
+Patch13013: powerpc-Fix-deadlock-in-icswx-code.patch
+
+Patch13014: iwlagn-fix-ht_params-NULL-pointer-dereference.patch
 
 Patch20000: utrace.patch
 
@@ -675,44 +660,16 @@ Patch20000: utrace.patch
 Patch21000: arm-omap-dt-compat.patch
 Patch21001: arm-smsc-support-reading-mac-address-from-device-tree.patch
 
-# workaround for issue with gcc-4.6.x
-# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45819
-# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45704
-# patch from http://www.delorie.com/tmp/arm-readl.patch
-Patch21002: arm-readl.patch
-
-Patch21003: TEGRA-2.6.40.2-enable-USB-ports.patch
-
-# rhbz#719607
-Patch21004: vfs-fix-automount-for-negative-autofs-dentries.patch
-
-# rhbz #740645
-Patch21011: md-dont-delay-reboot-by-1-second-if-no-MD-devices.patch
-
-# rhbz #496975
-Patch21013: Platform-fix-samsung-laptop-DMI-identification-for-N.patch
-
-# rhbz #700718
-Patch21015: x86-Save-stack-pointer-in-perf-live-regs-savings.patch
-Patch21016: x86-Fetch-stack-from-regs-when-possible-in-dump_trac.patch
-
-#rhbz #708563
-Patch21017: binfmt_elf-fix-PIE-execution-with-random-disabled.patch
-
 #rhbz #722509
-Patch21018: mmc-Always-check-for-lower-base-frequency-quirk-for-.patch
+Patch21002: mmc-Always-check-for-lower-base-frequency-quirk-for-.patch
 
 #rhbz #735946
 Patch21020: 0001-mm-vmscan-Limit-direct-reclaim-for-higher-order-allo.patch
 Patch21021: 0002-mm-Abort-reclaim-compaction-if-compaction-can-procee.patch
 
-#rhbz 737108
-Patch21030: platform-fix-samsung-brightness-min-max-calculations.patch
-
 #rhbz 748691
-Patch21040: be2net-move-to-new-vlan-model.patch
-Patch21041: be2net-non-member-vlan-pkts-not-received-in-promisco.patch
-Patch21042: benet-remove-bogus-unlikely-on-vlan-check.patch
+Patch21030: be2net-non-member-vlan-pkts-not-received-in-promisco.patch
+Patch21031: benet-remove-bogus-unlikely-on-vlan-check.patch
 
 #rhbz 749166
 Patch21050: xfs-Fix-possible-memory-corruption-in-xfs_readlink.patch
@@ -725,6 +682,9 @@ Patch21071: WMI-properly-cleanup-devices-to-avoid-crashes.patch
 #rhbz 728607
 Patch21060: elantech.patch
 
+#rhbz 748210
+Patch21061: ideapad-Check-if-acpi-already-handle-backlight.patch
+
 %endif
 
 BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root
@@ -776,7 +736,7 @@ operate.
 %package bootwrapper
 Summary: Boot wrapper files for generating combined kernel + initrd images
 Group: Development/System
-Requires: gzip
+Requires: gzip binutils
 %description bootwrapper
 Kernel-bootwrapper contains the wrapper code which makes bootable "zImage"
 files combining both kernel and initial ramdisk.
@@ -845,8 +805,7 @@ AutoReqProv: no\
 Requires(pre): /usr/bin/find\
 Requires: perl\
 %description -n kernel%{?variant}%{?1:-%{1}}-devel\
-This package provides kernel headers and 
-makefiles sufficient to build modules\
+This package provides kernel headers and makefiles sufficient to build modules\
 against the %{?2:%{2} }kernel package.\
 %{nil}
 
@@ -1118,26 +1077,21 @@ ApplyOptionalPatch linux-2.6-compile-fixes.patch
 ApplyOptionalPatch linux-2.6-upstream-reverts.patch -R
 
 
-ApplyPatch perf-check-ownership.patch
-
-#
-# SPARC64
-#
-ApplyPatch linux-2.6.29-sparc-IOC_TYPECHECK.patch
+# Architecture patches
+# x86(-64)
 
 #
 # ARM
 #
 ApplyPatch arm-omap-dt-compat.patch
 ApplyPatch arm-smsc-support-reading-mac-address-from-device-tree.patch
-ApplyPatch arm-readl.patch
-ApplyPatch TEGRA-2.6.40.2-enable-USB-ports.patch
 
+ApplyPatch taint-vbox.patch
 #
-# Exec shield
+# NX Emulation
 #
-ApplyPatch linux-2.6-i386-nx-emulation.patch
 ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch
+ApplyPatch linux-2.6-i386-nx-emulation.patch
 
 #
 # bugfixes to drivers and filesystems
@@ -1162,14 +1116,12 @@ ApplyPatch xfs-Fix-possible-memory-corruption-in-xfs_readlink.patch
 # ACPI
 ApplyPatch linux-2.6-defaults-acpi-video.patch
 ApplyPatch linux-2.6-acpi-video-dos.patch
-ApplyPatch acpi-ec-add-delay-before-write.patch
 ApplyPatch linux-2.6-acpi-debug-infinite-loop.patch
 ApplyPatch acpi-ensure-thermal-limits-match-cpu-freq.patch
 ApplyPatch acpi-sony-nonvs-blacklist.patch
 
 # Various low-impact patches to aid debugging.
 ApplyPatch linux-2.6-debug-taint-vm.patch
-ApplyPatch linux-2.6-debug-vm-would-have-oomkilled.patch
 
 #
 # PCI
@@ -1184,10 +1136,10 @@ ApplyPatch linux-2.6-defaults-aspm.patch
 # ACPI
 
 # ALSA
-ApplyPatch hda_intel-prealloc-4mb-dmabuffer.patch
 
 # Networking
 
+
 # Misc fixes
 # The input layer spews crap no-one cares about.
 ApplyPatch linux-2.6-input-kill-stupid-messages.patch
@@ -1207,9 +1159,6 @@ ApplyPatch linux-2.6-silence-noise.patch
 # Make fbcon not show the penguins with 'quiet'
 ApplyPatch linux-2.6-silence-fbcon-logo.patch
 
-# Get rid of useless bridge window conflict warnings
-ApplyPatch x86-pci-reduce-severity-of-host-bridge-window-conflict-warnings.patch
-
 # Changes to upstream defaults.
 
 
@@ -1232,14 +1181,13 @@ ApplyOptionalPatch drm-nouveau-updates.patch
 # Intel DRM
 ApplyOptionalPatch drm-intel-next.patch
 ApplyPatch drm-intel-make-lvds-work.patch
+ApplyPatch drm-i915-fbc-stfu.patch
 ApplyPatch drm-i915-sdvo-lvds-is-digital.patch
 
 ApplyPatch drm-lower-severity-radeon-lockup.diff
 
 ApplyPatch linux-2.6-intel-iommu-igfx.patch
 
-ApplyPatch block-stray-block-put-after-teardown.patch
-
 # silence the ACPI blacklist code
 ApplyPatch linux-2.6-silence-acpi-blacklist.patch
 
@@ -1249,61 +1197,52 @@ ApplyOptionalPatch linux-2.6-v4l-dvb-fixes.patch
 ApplyOptionalPatch linux-2.6-v4l-dvb-update.patch
 ApplyOptionalPatch linux-2.6-v4l-dvb-experimental.patch
 
-ApplyPatch media-DiBcom-protect-the-I2C-bufer-access.patch
-ApplyPatch media-dib0700-protect-the-dib0700-buffer-access.patch
-ApplyPatch media-dib0700-correct-error-message.patch
-
-# Avoid false quiescent states in rcu.
+# Patches headed upstream
 ApplyPatch rcutree-avoid-false-quiescent-states.patch
 
-# Patches headed upstream
 ApplyPatch disable-i8042-check-on-apple-mac.patch
 
 ApplyPatch add-appleir-usb-driver.patch
 
+ApplyPatch udlfb-bind-framebuffer-to-interface.patch
 ApplyPatch ums-realtek-driver-uses-stack-memory-for-DMA.patch
+ApplyPatch epoll-fix-spurious-lockdep-warnings.patch
+ApplyPatch epoll-limit-paths.patch
+ApplyPatch rcu-avoid-just-onlined-cpu-resched.patch
+ApplyPatch block-stray-block-put-after-teardown.patch
 ApplyPatch usb-add-quirk-for-logitech-webcams.patch
+
 ApplyPatch crypto-register-cryptd-first.patch
-ApplyPatch x86-p4-make-watchdog-and-perf-work-together.patch
 
 # rhbz#605888
 ApplyPatch dmar-disable-when-ricoh-multifunction.patch
 
-ApplyPatch epoll-fix-spurious-lockdep-warnings.patch
-ApplyPatch epoll-limit-paths.patch
-
-ApplyPatch iwlagn-check-for-priv--txq-in-iwlagn_wait_tx_queue_empty.patch
-
-ApplyPatch utrace.patch
-
-# rhbz#719607
-ApplyPatch vfs-fix-automount-for-negative-autofs-dentries.patch
+ApplyPatch revert-efi-rtclock.patch
+ApplyPatch efi-dont-map-boot-services-on-32bit.patch
 
-#rhbz 740645
-ApplyPatch md-dont-delay-reboot-by-1-second-if-no-MD-devices.patch
+ApplyPatch add-macbookair41-keyboard.patch
 
-# rhbz #496675
-ApplyPatch Platform-fix-samsung-laptop-DMI-identification-for-N.patch
+ApplyPatch hvcs_pi_buf_alloc.patch
 
-# rhbz #700718
-ApplyPatch x86-Save-stack-pointer-in-perf-live-regs-savings.patch
-ApplyPatch x86-Fetch-stack-from-regs-when-possible-in-dump_trac.patch
+ApplyPatch powerpc-Fix-deadlock-in-icswx-code.patch
 
-#rhbz #708563
-ApplyPatch binfmt_elf-fix-PIE-execution-with-random-disabled.patch
+ApplyPatch iwlagn-fix-ht_params-NULL-pointer-dereference.patch
 
 #rhbz #722509
 ApplyPatch mmc-Always-check-for-lower-base-frequency-quirk-for-.patch
 
+ApplyPatch media-DiBcom-protect-the-I2C-bufer-access.patch
+ApplyPatch media-dib0700-protect-the-dib0700-buffer-access.patch
+ApplyPatch media-dib0700-correct-error-message.patch
+
+# utrace.
+ApplyPatch utrace.patch
+
 #rhbz #735946
 ApplyPatch 0001-mm-vmscan-Limit-direct-reclaim-for-higher-order-allo.patch
 ApplyPatch 0002-mm-Abort-reclaim-compaction-if-compaction-can-procee.patch
 
-#rhbz 737108
-ApplyPatch platform-fix-samsung-brightness-min-max-calculations.patch
-
 #rhbz 748691
-ApplyPatch be2net-move-to-new-vlan-model.patch
 ApplyPatch be2net-non-member-vlan-pkts-not-received-in-promisco.patch
 ApplyPatch benet-remove-bogus-unlikely-on-vlan-check.patch
 
@@ -1316,6 +1255,9 @@ ApplyPatch WMI-properly-cleanup-devices-to-avoid-crashes.patch
 #rhbz 728607
 ApplyPatch elantech.patch
 
+#rhbz 748210
+ApplyPatch ideapad-Check-if-acpi-already-handle-backlight.patch
+
 # END OF PATCH APPLICATIONS
 
 %endif
@@ -1936,6 +1878,9 @@ fi
 # and build.
 
 %changelog
+* Mon Nov 07 2011 Dave Jones <davej at redhat.com>
+- Rebase to 3.1.0
+
 * Thu Nov 03 2011 Josh Boyer <jwboyer at redhat.com>
 - Add patches queued for 3.2 for elantech driver (rhbz 728607)
 
diff --git a/linux-2.6-crash-driver.patch b/linux-2.6-crash-driver.patch
index b8377d3..239f0f6 100644
--- a/linux-2.6-crash-driver.patch
+++ b/linux-2.6-crash-driver.patch
@@ -1,17 +1,17 @@
-From df42d15cd28f468ecd4c30465b98a53cce90617c Mon Sep 17 00:00:00 2001
+From f72d640713d01b3b704c6e84ab49b62f19fc9c22 Mon Sep 17 00:00:00 2001
 From: Kyle McMartin <kyle at phobos.i.jkkm.org>
 Date: Tue, 30 Mar 2010 00:16:25 -0400
-Subject: dev-crash-driver.patch
+Subject: [PATCH] dev-crash-driver.patch
 
 ---
  arch/ia64/include/asm/crash.h |   90 +++++++++++++++++++++++++++++
  arch/ia64/kernel/ia64_ksyms.c |    3 +
  arch/x86/include/asm/crash.h  |   75 ++++++++++++++++++++++++
  arch/x86/mm/ioremap.c         |    2 +
- drivers/char/Kconfig          |    2 +
+ drivers/char/Kconfig          |    3 +
  drivers/char/Makefile         |    2 +
  drivers/char/crash.c          |  128 +++++++++++++++++++++++++++++++++++++++++
- 7 files changed, 302 insertions(+), 0 deletions(-)
+ 7 files changed, 303 insertions(+), 0 deletions(-)
  create mode 100644 arch/ia64/include/asm/crash.h
  create mode 100644 arch/x86/include/asm/crash.h
  create mode 100644 drivers/char/crash.c
@@ -208,7 +208,7 @@ index 0000000..dfcc006
 +
 +#endif /* _ASM_I386_CRASH_H */
 diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
-index 5eb1ba7..3e525d2 100644
+index be1ef57..ac659f7 100644
 --- a/arch/x86/mm/ioremap.c
 +++ b/arch/x86/mm/ioremap.c
 @@ -24,6 +24,8 @@
@@ -220,6 +220,30 @@ index 5eb1ba7..3e525d2 100644
  /*
   * Fix up the linear direct mapping of the kernel to avoid cache attribute
   * conflicts.
+diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
+index 423fd56..e04a561 100644
+--- a/drivers/char/Kconfig
++++ b/drivers/char/Kconfig
+@@ -4,6 +4,9 @@
+ 
+ menu "Character devices"
+ 
++config CRASH
++	tristate "Crash Utility memory driver"
++
+ source "drivers/tty/Kconfig"
+ 
+ config DEVKMEM
+diff --git a/drivers/char/Makefile b/drivers/char/Makefile
+index 32762ba..3d5d525 100644
+--- a/drivers/char/Makefile
++++ b/drivers/char/Makefile
+@@ -65,3 +65,5 @@ obj-$(CONFIG_JS_RTC)		+= js-rtc.o
+ js-rtc-y = rtc.o
+ 
+ obj-$(CONFIG_TILE_SROM)		+= tile-srom.o
++
++obj-$(CONFIG_CRASH)            += crash.o
 diff --git a/drivers/char/crash.c b/drivers/char/crash.c
 new file mode 100644
 index 0000000..e5437de
@@ -354,29 +378,6 @@ index 0000000..e5437de
 +module_exit(crash_cleanup_module);
 +
 +MODULE_LICENSE("GPL");
+-- 
+1.7.6
 
-diff --git a/drivers/char/Makefile b/drivers/char/Makefile
-index ba53ec9..6588b33 100644
---- a/drivers/char/Makefile
-+++ b/drivers/char/Makefile
-@@ -98,3 +98,5 @@ obj-$(CONFIG_RAMOOPS)		+= ramoops.o
- 
- obj-$(CONFIG_JS_RTC)		+= js-rtc.o
- js-rtc-y = rtc.o
-+
-+obj-$(CONFIG_CRASH)		+= crash.o
-
-diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
-index 04f8b2d..e8fb997 100644
---- a/drivers/char/Kconfig
-+++ b/drivers/char/Kconfig
-@@ -4,6 +4,9 @@
- 
- menu "Character devices"
- 
-+config CRASH
-+	tristate "Crash Utility memory driver"
-+
- source "drivers/tty/Kconfig"
- 
- config DEVKMEM
diff --git a/linux-2.6-intel-iommu-igfx.patch b/linux-2.6-intel-iommu-igfx.patch
index 44fd141..b2f8f19 100644
--- a/linux-2.6-intel-iommu-igfx.patch
+++ b/linux-2.6-intel-iommu-igfx.patch
@@ -43,8 +43,8 @@ index e7848a0..9914485 100644
  			for io virtual address below 32 bit forcing dual
 diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
 index 4173125..8f36786 100644
---- a/drivers/pci/intel-iommu.c
-+++ b/drivers/pci/intel-iommu.c
+--- a/drivers/iommu/intel-iommu.c
++++ b/drivers/iommu/intel-iommu.c
 @@ -340,7 +340,8 @@ int dmar_disabled = 0;
  int dmar_disabled = 1;
  #endif /*CONFIG_DMAR_DEFAULT_ON*/
diff --git a/linux-2.6-silence-noise.patch b/linux-2.6-silence-noise.patch
index 8aba3cd..1e4d7c5 100644
--- a/linux-2.6-silence-noise.patch
+++ b/linux-2.6-silence-noise.patch
@@ -46,8 +46,8 @@ Signed-off-by: Dave Jones <davej at redhat.com>
 +		 * In case of error we but don't return the error code immediately.
 +		 * Below we will return -EPROTONOSUPPORT
  		 */
--		if (err && printk_ratelimit())
--			printk(KERN_ERR "can: request_module "
+-		if (err)
+-			printk_ratelimited(KERN_ERR "can: request_module "
 -			       "(can-proto-%d) failed.\n", protocol);
  
  		cp = can_get_proto(protocol);
diff --git a/linux-2.6.30-no-pcspkr-modalias.patch b/linux-2.6.30-no-pcspkr-modalias.patch
index c703b88..439269c 100644
--- a/linux-2.6.30-no-pcspkr-modalias.patch
+++ b/linux-2.6.30-no-pcspkr-modalias.patch
@@ -1,11 +1,12 @@
-diff -up linux-2.6.30.noarch/drivers/input/misc/pcspkr.c.jx linux-2.6.30.noarch/drivers/input/misc/pcspkr.c
---- linux-2.6.30.noarch/drivers/input/misc/pcspkr.c.jx	2009-07-28 16:54:44.000000000 -0400
-+++ linux-2.6.30.noarch/drivers/input/misc/pcspkr.c	2009-07-28 16:59:36.000000000 -0400
-@@ -23,7 +23,6 @@
+diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
+index 34f4d2e..3e40c70 100644
+--- a/drivers/input/misc/pcspkr.c
++++ b/drivers/input/misc/pcspkr.c
+@@ -24,7 +24,6 @@
  MODULE_AUTHOR("Vojtech Pavlik <vojtech at ucw.cz>");
  MODULE_DESCRIPTION("PC Speaker beeper driver");
  MODULE_LICENSE("GPL");
 -MODULE_ALIAS("platform:pcspkr");
  
- #if defined(CONFIG_MIPS) || defined(CONFIG_X86)
- /* Use the global PIT lock ! */
+ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+ {
diff --git a/media-DiBcom-protect-the-I2C-bufer-access.patch b/media-DiBcom-protect-the-I2C-bufer-access.patch
index dc988bb..1b2a54b 100644
--- a/media-DiBcom-protect-the-I2C-bufer-access.patch
+++ b/media-DiBcom-protect-the-I2C-bufer-access.patch
@@ -1,7 +1,10 @@
-From 4aa9d354534c2fcbb06170f5968f762aa9bdd0f6 Mon Sep 17 00:00:00 2001
 From: Patrick Boettcher <Patrick.Boettcher at dibcom.fr>
-Date: Wed, 3 Aug 2011 15:08:21 -0300
-Subject: [PATCH 1/3] [media] DiBcom: protect the I2C bufer access
+Date: Wed, 3 Aug 2011 15:08:21 +0000 (-0300)
+Subject: [media] DiBcom: protect the I2C bufer access
+X-Git-Tag: next-20110927~67^2~4^2~225
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fnext%2Flinux-next.git;a=commitdiff_plain;h=79fcce3230b140f7675f8529ee53fe2f9644f902
+
+[media] DiBcom: protect the I2C bufer access
 
 This patch protects the I2C buffer access in order to manage concurrent
 access. This protection is done using mutex.
@@ -16,15 +19,6 @@ Signed-off-by: Olivier Grenie <olivier.grenie at dibcom.fr>
 Signed-off-by: Patrick Boettcher <Patrick.Boettcher at dibcom.fr>
 Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
 ---
- drivers/media/dvb/frontends/dib0070.c        |   37 +++++-
- drivers/media/dvb/frontends/dib0090.c        |   70 +++++++++--
- drivers/media/dvb/frontends/dib7000m.c       |   27 ++++-
- drivers/media/dvb/frontends/dib7000p.c       |   32 +++++-
- drivers/media/dvb/frontends/dib8000.c        |   72 ++++++++++--
- drivers/media/dvb/frontends/dib9000.c        |  164 +++++++++++++++++++++++---
- drivers/media/dvb/frontends/dibx000_common.c |   76 ++++++++++--
- drivers/media/dvb/frontends/dibx000_common.h |    1 +
- 8 files changed, 412 insertions(+), 67 deletions(-)
 
 diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
 index 1d47d4d..dc1cb17 100644
@@ -341,7 +335,7 @@ index 79cb1c2..dbb76d7 100644
  	st->timf_default = cfg->bw->timf;
  
 diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
-index 0c9f40c..292bc19 100644
+index a64a538..4eb9c2b 100644
 --- a/drivers/media/dvb/frontends/dib7000p.c
 +++ b/drivers/media/dvb/frontends/dib7000p.c
 @@ -10,6 +10,7 @@
@@ -434,8 +428,8 @@ index 0c9f40c..292bc19 100644
 +	   more common) */
 +	st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
  
- 	dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
- 
+ 	/* FIXME: make sure the dev.parent field is initialized, or else
+ 	   request_firmware() will hit an OOPS (this should be moved somewhere
 diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c
 index 7d2ea11..fe284d5 100644
 --- a/drivers/media/dvb/frontends/dib8000.c
@@ -1154,6 +1148,3 @@ index f031165..5e01147 100644
  };
  
  extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
--- 
-1.7.6.4
-
diff --git a/media-dib0700-correct-error-message.patch b/media-dib0700-correct-error-message.patch
index f40a4fa..5e5d3bf 100644
--- a/media-dib0700-correct-error-message.patch
+++ b/media-dib0700-correct-error-message.patch
@@ -1,7 +1,10 @@
-From e4f0158142e4b23939d9444d8af80ff20692f7a5 Mon Sep 17 00:00:00 2001
 From: Olivier Grenie <olivier.grenie at dibcom.fr>
-Date: Thu, 4 Aug 2011 16:10:03 -0300
-Subject: [PATCH 3/3] [media] dib0700: correct error message
+Date: Thu, 4 Aug 2011 16:10:03 +0000 (-0300)
+Subject: [media] dib0700: correct error message
+X-Git-Tag: next-20110927~67^2~4^2~223
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fnext%2Flinux-next.git;a=commitdiff_plain;h=680417bb318adc5f1f8f392730776176fbcdedd8
+
+[media] dib0700: correct error message
 
 The goal of this patch is to correct a previous patch. In case of error,
 the err() function should be used instead of dprintk() function.
@@ -12,8 +15,6 @@ the err() function should be used instead of dprintk() function.
 Signed-off-by: Olivier Grenie <olivier.grenie at dibcom.fr>
 Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
 ---
- drivers/media/dvb/dvb-usb/dib0700_core.c |   18 +++++++++---------
- 1 files changed, 9 insertions(+), 9 deletions(-)
 
 diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
 index a224e94..b693ed1 100644
@@ -100,6 +101,3 @@ index a224e94..b693ed1 100644
  		return 0;
  	}
  
--- 
-1.7.6.4
-
diff --git a/media-dib0700-protect-the-dib0700-buffer-access.patch b/media-dib0700-protect-the-dib0700-buffer-access.patch
index e63f58c..109cab8 100644
--- a/media-dib0700-protect-the-dib0700-buffer-access.patch
+++ b/media-dib0700-protect-the-dib0700-buffer-access.patch
@@ -1,7 +1,10 @@
-From 9e3419029b4c660298928a6f03002daae6c055a6 Mon Sep 17 00:00:00 2001
 From: Olivier Grenie <olivier.grenie at dibcom.fr>
-Date: Mon, 1 Aug 2011 15:45:58 -0300
-Subject: [PATCH 2/3] [media] dib0700: protect the dib0700 buffer access
+Date: Mon, 1 Aug 2011 15:45:58 +0000 (-0300)
+Subject: [media] dib0700: protect the dib0700 buffer access
+X-Git-Tag: next-20110927~67^2~4^2~224
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fnext%2Flinux-next.git;a=commitdiff_plain;h=bff469f4167fdabfe15294f375577d7eadbaa1bb
+
+[media] dib0700: protect the dib0700 buffer access
 
 This patch protects the common buffer access inside the dib0700 in order
 to manage concurrent access. This protection is done using mutex.
@@ -15,8 +18,6 @@ Signed-off-by: Patrick Boettcher <patrick.boettcher at dibcom.fr>
 [mchehab at redhat.com: dprint requires 3 arguments. Replaced by dib_info]
 Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
 ---
- drivers/media/dvb/dvb-usb/dib0700_core.c |   81 ++++++++++++++++++++++++++---
- 1 files changed, 72 insertions(+), 9 deletions(-)
 
 diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
 index 5eb91b4..a224e94 100644
@@ -245,6 +246,3 @@ index 5eb91b4..a224e94 100644
  	return ret;
  }
  
--- 
-1.7.6.4
-
diff --git a/powerpc-Fix-deadlock-in-icswx-code.patch b/powerpc-Fix-deadlock-in-icswx-code.patch
new file mode 100644
index 0000000..a2ce3cf
--- /dev/null
+++ b/powerpc-Fix-deadlock-in-icswx-code.patch
@@ -0,0 +1,74 @@
+From patchwork Wed Sep 14 19:43:15 2011
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: powerpc: Fix deadlock in icswx code
+Date: Wed, 14 Sep 2011 09:43:15 -0000
+From: Anton Blanchard <anton at samba.org>
+X-Patchwork-Id: 114701
+Message-Id: <20110915054315.5e5ae062 at kryten>
+To: benh at kernel.crashing.org, paulus at samba.org
+Cc: linuxppc-dev at lists.ozlabs.org
+
+The icswx code introduced an A-B B-A deadlock:
+
+     CPU0                    CPU1
+     ----                    ----
+lock(&anon_vma->mutex);
+                             lock(&mm->mmap_sem);
+                             lock(&anon_vma->mutex);
+lock(&mm->mmap_sem);
+
+Instead of using the mmap_sem to keep mm_users constant, take the
+page table spinlock.
+
+Signed-off-by: Anton Blanchard <anton at samba.org>
+Cc: <stable at kernel.org>
+
+---
+
+
+diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c
+index 3bafc3d..4ff587e 100644
+--- a/arch/powerpc/mm/mmu_context_hash64.c
++++ b/arch/powerpc/mm/mmu_context_hash64.c
+@@ -136,8 +136,8 @@ int use_cop(unsigned long acop, struct mm_struct *mm)
+ 	if (!mm || !acop)
+ 		return -EINVAL;
+ 
+-	/* We need to make sure mm_users doesn't change */
+-	down_read(&mm->mmap_sem);
++	/* The page_table_lock ensures mm_users won't change under us */
++	spin_lock(&mm->page_table_lock);
+ 	spin_lock(mm->context.cop_lockp);
+ 
+ 	if (mm->context.cop_pid == COP_PID_NONE) {
+@@ -164,7 +164,7 @@ int use_cop(unsigned long acop, struct mm_struct *mm)
+ 
+ out:
+ 	spin_unlock(mm->context.cop_lockp);
+-	up_read(&mm->mmap_sem);
++	spin_unlock(&mm->page_table_lock);
+ 
+ 	return ret;
+ }
+@@ -185,8 +185,8 @@ void drop_cop(unsigned long acop, struct mm_struct *mm)
+ 	if (WARN_ON_ONCE(!mm))
+ 		return;
+ 
+-	/* We need to make sure mm_users doesn't change */
+-	down_read(&mm->mmap_sem);
++	/* The page_table_lock ensures mm_users won't change under us */
++	spin_lock(&mm->page_table_lock);
+ 	spin_lock(mm->context.cop_lockp);
+ 
+ 	mm->context.acop &= ~acop;
+@@ -213,7 +213,7 @@ void drop_cop(unsigned long acop, struct mm_struct *mm)
+ 	}
+ 
+ 	spin_unlock(mm->context.cop_lockp);
+-	up_read(&mm->mmap_sem);
++	spin_unlock(&mm->page_table_lock);
+ }
+ EXPORT_SYMBOL_GPL(drop_cop);
+ 
diff --git a/rcu-avoid-just-onlined-cpu-resched.patch b/rcu-avoid-just-onlined-cpu-resched.patch
new file mode 100644
index 0000000..517f375
--- /dev/null
+++ b/rcu-avoid-just-onlined-cpu-resched.patch
@@ -0,0 +1,47 @@
+rcu: Avoid having just-onlined CPU resched itself when RCU is idle
+
+CPUs set rdp->qs_pending when coming online to resolve races with
+grace-period start.  However, this means that if RCU is idle, the
+just-onlined CPU might needlessly send itself resched IPIs.  Adjust
+the online-CPU initialization to avoid this, and also to correctly
+cause the CPU to respond to the current grace period if needed.
+
+Signed-off-by: Paul E. McKenney <paulmck at linux.vnet.ibm.com>
+---
+ kernel/rcutree.c |   13 +++++++++----
+ 1 files changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/kernel/rcutree.c b/kernel/rcutree.c
+index ba06207..472d6b2 100644
+--- a/kernel/rcutree.c
++++ b/kernel/rcutree.c
+@@ -1865,8 +1865,6 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
+ 
+ 	/* Set up local state, ensuring consistent view of global state. */
+ 	raw_spin_lock_irqsave(&rnp->lock, flags);
+-	rdp->passed_quiesc = 0;  /* We could be racing with new GP, */
+-	rdp->qs_pending = 1;	 /*  so set up to respond to current GP. */
+ 	rdp->beenonline = 1;	 /* We have now been online. */
+ 	rdp->preemptible = preemptible;
+ 	rdp->qlen_last_fqs_check = 0;
+@@ -1891,8 +1889,15 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
+ 		rnp->qsmaskinit |= mask;
+ 		mask = rnp->grpmask;
+ 		if (rnp == rdp->mynode) {
+-			rdp->gpnum = rnp->completed; /* if GP in progress... */
+-			rdp->completed = rnp->completed;
++			/*
++			 * If there is a grace period in progress, we will
++			 * set up to wait for it next time we run the
++			 * RCU core code.
++			 */
++			rdp->gpnum = rnp->completed;
++ 			rdp->completed = rnp->completed;
++			rdp->passed_quiesc = 0;
++			rdp->qs_pending = 0;
+ 			rdp->passed_quiesc_completed = rnp->completed - 1;
+ 		}
+ 		raw_spin_unlock(&rnp->lock); /* irqs already disabled. */
+-- 
+1.7.6
+
diff --git a/revert-efi-rtclock.patch b/revert-efi-rtclock.patch
new file mode 100644
index 0000000..87ecaa1
--- /dev/null
+++ b/revert-efi-rtclock.patch
@@ -0,0 +1,76 @@
+diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
+index 3ae4128..e17c6d2 100644
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -89,50 +89,26 @@ early_param("add_efi_memmap", setup_add_efi_memmap);
+ 
+ static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+ {
+-	unsigned long flags;
+-	efi_status_t status;
+-
+-	spin_lock_irqsave(&rtc_lock, flags);
+-	status = efi_call_virt2(get_time, tm, tc);
+-	spin_unlock_irqrestore(&rtc_lock, flags);
+-	return status;
++	return efi_call_virt2(get_time, tm, tc);
+ }
+ 
+ static efi_status_t virt_efi_set_time(efi_time_t *tm)
+ {
+-	unsigned long flags;
+-	efi_status_t status;
+-
+-	spin_lock_irqsave(&rtc_lock, flags);
+-	status = efi_call_virt1(set_time, tm);
+-	spin_unlock_irqrestore(&rtc_lock, flags);
+-	return status;
++	return efi_call_virt1(set_time, tm);
+ }
+ 
+ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
+ 					     efi_bool_t *pending,
+ 					     efi_time_t *tm)
+ {
+-	unsigned long flags;
+-	efi_status_t status;
+-
+-	spin_lock_irqsave(&rtc_lock, flags);
+-	status = efi_call_virt3(get_wakeup_time,
+-				enabled, pending, tm);
+-	spin_unlock_irqrestore(&rtc_lock, flags);
+-	return status;
++	return efi_call_virt3(get_wakeup_time,
++			      enabled, pending, tm);
+ }
+ 
+ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
+ {
+-	unsigned long flags;
+-	efi_status_t status;
+-
+-	spin_lock_irqsave(&rtc_lock, flags);
+-	status = efi_call_virt2(set_wakeup_time,
+-				enabled, tm);
+-	spin_unlock_irqrestore(&rtc_lock, flags);
+-	return status;
++	return efi_call_virt2(set_wakeup_time,
++			      enabled, tm);
+ }
+ 
+ static efi_status_t virt_efi_get_variable(efi_char16_t *name,
+@@ -232,14 +208,11 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
+ static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
+ 					     efi_time_cap_t *tc)
+ {
+-	unsigned long flags;
+ 	efi_status_t status;
+ 
+-	spin_lock_irqsave(&rtc_lock, flags);
+ 	efi_call_phys_prelog();
+ 	status = efi_call_phys2(efi_phys.get_time, tm, tc);
+ 	efi_call_phys_epilog();
+-	spin_unlock_irqrestore(&rtc_lock, flags);
+ 	return status;
+ }
+ 
diff --git a/scripts/grab-logs.sh b/scripts/grab-logs.sh
index 8a445ec..5df5735 100755
--- a/scripts/grab-logs.sh
+++ b/scripts/grab-logs.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-VER=$(make verrel)
+VER=$(fedpkg verrel)
 ver=$(echo $VER | sed -e 's/-/ /g' | awk '{print $2}')
 rev=$(echo $VER | sed -e 's/-/ /g' | awk '{print $3}')
 
diff --git a/sources b/sources
index 6dcaf1f..9529d7a 100644
--- a/sources
+++ b/sources
@@ -1,2 +1 @@
-398e95866794def22b12dfbc15ce89c0  linux-3.0.tar.bz2
-49618d8c7a71549c8870eb709c7d3f81  patch-3.0.8.bz2
+8d43453f8159b2332ad410b19d86a931  linux-3.1.tar.bz2
diff --git a/taint-vbox.patch b/taint-vbox.patch
new file mode 100644
index 0000000..5cb3e47
--- /dev/null
+++ b/taint-vbox.patch
@@ -0,0 +1,15 @@
+diff --git a/kernel/module.c b/kernel/module.c
+index 04379f92..d26c9a3 100644
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -2653,6 +2653,10 @@ static int check_module_license_and_versions(struct module *mod)
+ 	if (strcmp(mod->name, "ndiswrapper") == 0)
+ 		add_taint(TAINT_PROPRIETARY_MODULE);
+ 
++	/* vbox is garbage. */
++	if (strcmp(mod->name, "vboxdrv") == 0)
++		add_taint(TAINT_CRAP);
++
+ 	/* driverloader was caught wrongly pretending to be under GPL */
+ 	if (strcmp(mod->name, "driverloader") == 0)
+ 		add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
diff --git a/udlfb-bind-framebuffer-to-interface.patch b/udlfb-bind-framebuffer-to-interface.patch
new file mode 100644
index 0000000..1c5c6df
--- /dev/null
+++ b/udlfb-bind-framebuffer-to-interface.patch
@@ -0,0 +1,33 @@
+From c91a793f66d5b06292aa431ae3a36c8aca991fa3 Mon Sep 17 00:00:00 2001
+From: Kay Sievers <kay.sievers at vrfy.org>
+Date: Tue, 5 Jul 2011 17:04:11 -0700
+Subject: [PATCH] drivers/video/udlfb bind framebuffer to interface.
+
+Udlfb has been binding the framebuffer device to its parent, which
+isn't correct and causes confusion with operations like udev remove.
+
+Coming plug and play multiseat support is dependent on this fix.
+
+Signed-off-by: Kay Sievers <kay.sievers at vrfy.org>
+Signed-off-by: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Paul Mundt <lethal at linux-sh.org>
+---
+ drivers/video/udlfb.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
+index 816a4fd..c6584c9 100644
+--- a/drivers/video/udlfb.c
++++ b/drivers/video/udlfb.c
+@@ -1549,7 +1549,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ 	/* We don't register a new USB class. Our client interface is fbdev */
+ 
+ 	/* allocates framebuffer driver structure, not framebuffer memory */
+-	info = framebuffer_alloc(0, &usbdev->dev);
++	info = framebuffer_alloc(0, &interface->dev);
+ 	if (!info) {
+ 		retval = -ENOMEM;
+ 		pr_err("framebuffer_alloc failed\n");
+-- 
+1.7.4.4
+
diff --git a/ums-realtek-driver-uses-stack-memory-for-DMA.patch b/ums-realtek-driver-uses-stack-memory-for-DMA.patch
index 2564fdb..98c8b0c 100644
--- a/ums-realtek-driver-uses-stack-memory-for-DMA.patch
+++ b/ums-realtek-driver-uses-stack-memory-for-DMA.patch
@@ -1,22 +1,69 @@
-commit 82e632009bb7d6b97f8cabe9918c82703f4e5cd2
-Author: Josh Boyer <jwboyer at redhat.com>
-Date:   Tue Aug 2 08:37:53 2011 -0400
+From patchwork Tue Aug  2 05:04:11 2011
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 8bit
+Subject: ums-realtek driver uses stack memory for DMA
+Date: Tue, 02 Aug 2011 05:04:11 -0000
+From: Adam Cozzette <acozzette at cs.hmc.edu>
+X-Patchwork-Id: 1028062
+Message-Id: <20110802050411.GC3857@[192.168.0.12]>
+To: Josh Boyer <jwboyer at redhat.com>
+Cc: edwin_rong <edwin_rong at realsil.com.cn>, wwang <wei_wang at realsil.com.cn>, 
+ Greg Kroah-Hartman <gregkh at suse.de>, linux-usb at vger.kernel.org,
+ linux-kernel at vger.kernel.org
 
-    This patch changed rts51x_read_mem, rts51x_write_mem, and rts51x_read_status to
-    allocate temporary buffers with kmalloc. This way stack addresses are not used
-    for DMA when these functions call rts51x_bulk_transport.
-    
-    Signed-off-by: Adam Cozzette <acozzette at cs.hmc.edu>
-    Backported-by: Josh Boyer <jwboyer at redhat.com>
+On Mon, Aug 01, 2011 at 05:09:06PM -0400, Josh Boyer wrote:
+> Hello,
+> 
+> We have a report that the ums-realtek driver is generating a backtrace
+> due to using stack variables for DMA buffers.  The backtrace is below
+> and you can view the bug report here:
+> https://bugzilla.redhat.com/show_bug.cgi?id=720054
+> 
+> Looking through the code, it seems that every call to rts51x_read_mem,
+> rts51x_write_mem, and rts51x_read_status passes a stack variable to
+> rts51x_bulk_transport, which then calls usb_stor_bulk_transfer_buf with
+> this and generates the backtrace.  It is my understanding that the
+> driver should be passing variables that are not on the stack and have
+> been allocated with memory that will be suitable for the DMA api (e.g.
+> kmalloc).
+> 
+> Was this missed during the initial review and is anyone working on
+> adapting the driver to be compliant?
+
+Could you try out this patch if it looks ok to you? I have not tested it because
+unfortunately I don't have the hardware. Right now it generates some compile
+warnings like this one:
+
+drivers/usb/storage/realtek_cr.c:419:40: warning: ‘buf[0]’ may be used uninitialized in this function [-Wuninitialized]
+
+It think they are harmless but I didn't see an obvious way to get rid of them,
+so if you have any suggestions I would be glad to hear them.
+
+This patch changed rts51x_read_mem, rts51x_write_mem, and rts51x_read_status to
+allocate temporary buffers with kmalloc. This way stack addresses are not used
+for DMA when these functions call rts51x_bulk_transport.
+
+Signed-off-by: Adam Cozzette <acozzette at cs.hmc.edu>
+
+---
+realtek_cr.c |   35 ++++++++++++++++++++++++++++++-----
+ 1 file changed, 30 insertions(+), 5 deletions(-)
+
+--
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo at vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at  http://www.tux.org/lkml/
 
 diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
-index d509a4a..69a1bd3 100644
+index 34adc4b..232167a 100644
 --- a/drivers/usb/storage/realtek_cr.c
 +++ b/drivers/usb/storage/realtek_cr.c
-@@ -285,6 +285,11 @@ static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
+@@ -320,6 +320,11 @@ static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
  {
  	int retval;
- 	u8 cmnd[12] = {0};
+ 	u8 cmnd[12] = { 0 };
 +	u8 *buf;
 +
 +	buf = kmalloc(len, GFP_NOIO);
@@ -25,8 +72,8 @@ index d509a4a..69a1bd3 100644
  
  	US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len);
  
-@@ -296,10 +301,14 @@ static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
- 	cmnd[5] = (u8)len;
+@@ -331,10 +336,14 @@ static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
+ 	cmnd[5] = (u8) len;
  
  	retval = rts51x_bulk_transport(us, 0, cmnd, 12,
 -				       data, len, DMA_FROM_DEVICE, NULL);
@@ -42,10 +89,10 @@ index d509a4a..69a1bd3 100644
  	return 0;
  }
  
-@@ -307,6 +316,12 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
+@@ -342,6 +351,12 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
  {
  	int retval;
- 	u8 cmnd[12] = {0};
+ 	u8 cmnd[12] = { 0 };
 +	u8 *buf;
 +
 +	buf = kmalloc(len, GFP_NOIO);
@@ -55,8 +102,8 @@ index d509a4a..69a1bd3 100644
  
  	US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len);
  
-@@ -318,7 +333,8 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
- 	cmnd[5] = (u8)len;
+@@ -353,7 +368,8 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
+ 	cmnd[5] = (u8) len;
  
  	retval = rts51x_bulk_transport(us, 0, cmnd, 12,
 -				       data, len, DMA_TO_DEVICE, NULL);
@@ -65,10 +112,10 @@ index d509a4a..69a1bd3 100644
  	if (retval != USB_STOR_TRANSPORT_GOOD)
  		return -EIO;
  
-@@ -330,6 +346,11 @@ static int rts51x_read_status(struct us_data *us,
+@@ -365,6 +381,11 @@ static int rts51x_read_status(struct us_data *us,
  {
  	int retval;
- 	u8 cmnd[12] = {0};
+ 	u8 cmnd[12] = { 0 };
 +	u8 *buf;
 +
 +	buf = kmalloc(len, GFP_NOIO);
@@ -77,7 +124,7 @@ index d509a4a..69a1bd3 100644
  
  	US_DEBUGP("%s, lun = %d\n", __func__, lun);
  
-@@ -337,10 +358,14 @@ static int rts51x_read_status(struct us_data *us,
+@@ -372,10 +393,14 @@ static int rts51x_read_status(struct us_data *us,
  	cmnd[1] = 0x09;
  
  	retval = rts51x_bulk_transport(us, lun, cmnd, 12,
diff --git a/utrace.patch b/utrace.patch
index f70d0b1..576c737 100644
--- a/utrace.patch
+++ b/utrace.patch
@@ -1,42 +1,42 @@
-From davej  Sun Aug  7 15:19:08 2011
+From davej  Wed Aug  3 15:16:11 2011
 Return-Path: oleg at redhat.com
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:08 -0400 (EDT)
-Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
- zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:17:59 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:11 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
+ zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:15:37 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id F09A8A5D58;
-	Sun,  7 Aug 2011 15:17:58 -0400 (EDT)
-Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id 6mY7uBb0+l7B; Sun,  7 Aug 2011 15:17:58 -0400 (EDT)
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 92D6F9D8C5;
+	Wed,  3 Aug 2011 15:12:08 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id RRq2PiCBdMzK; Wed,  3 Aug 2011 15:12:08 -0400 (EDT)
 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id D1DFE9C7FA;
-	Sun,  7 Aug 2011 15:17:58 -0400 (EDT)
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 75C149D898;
+	Wed,  3 Aug 2011 15:12:08 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JHtc4027719;
-	Sun, 7 Aug 2011 15:17:56 -0400
+	by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JC01d029136;
+	Wed, 3 Aug 2011 15:12:01 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:19 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:17 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:09:28 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:26 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 01/22] utrace core
-Message-ID: <20110807191517.GA14365 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 01/31] utrace core
+Message-ID: <20110803190926.GA30903 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
 Status: RO
-Content-Length: 148212
-Lines: 4118
+Content-Length: 139951
+Lines: 3867
 
 From: Roland McGrath <roland at redhat.com>
 
@@ -59,11 +59,11 @@ the next patches try to fix this.
 
 This is is same/old utrace-core patch except:
 
-	- use group_stop/GROUP_STOP_DEQUEUED instead of removed
+	- use task->jobctl/JOBCTL_STOP_DEQUEUED instead of removed
 	  signal->flags/SIGNAL_STOP_DEQUEUED in utrace_get_signal()
 
-	- rediff the changes in tracehook.h against the current code
-	  without PT_PTRACED tweaks which were needed for ptrace-utrace
+	- do not include the tracehook changes, this comes with the
+	  next patches
 
 Signed-off-by: Roland McGrath <roland at redhat.com>
 Signed-off-by: Oleg Nesterov <oleg at redhat.com>
@@ -72,30 +72,28 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  Documentation/DocBook/utrace.tmpl |  589 +++++++++
  fs/proc/array.c                   |    3 +
  include/linux/sched.h             |    5 +
- include/linux/tracehook.h         |   85 ++-
  include/linux/utrace.h            |  692 +++++++++++
  init/Kconfig                      |    9 +
  kernel/Makefile                   |    1 +
- kernel/fork.c                     |    3 +
  kernel/utrace.c                   | 2440 +++++++++++++++++++++++++++++++++++++
- 10 files changed, 3827 insertions(+), 2 deletions(-)
+ 8 files changed, 3740 insertions(+), 1 deletions(-)
  create mode 100644 Documentation/DocBook/utrace.tmpl
  create mode 100644 include/linux/utrace.h
  create mode 100644 kernel/utrace.c
 
 diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
-index 3cebfa0..86c288b 100644
+index 66725a3..08ed954 100644
 --- a/Documentation/DocBook/Makefile
 +++ b/Documentation/DocBook/Makefile
 @@ -14,7 +14,7 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
  	    genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
  	    80211.xml debugobjects.xml sh.xml regulator.xml \
  	    alsa-driver-api.xml writing-an-alsa-driver.xml \
--	    tracepoint.xml media.xml drm.xml
-+	    tracepoint.xml utrace.xml media.xml drm.xml
+-	    tracepoint.xml drm.xml media_api.xml
++	    tracepoint.xml utrace.xml drm.xml media_api.xml
+ 
+ include $(srctree)/Documentation/DocBook/media/Makefile
  
- ###
- # The build process is as follows (targets):
 diff --git a/Documentation/DocBook/utrace.tmpl b/Documentation/DocBook/utrace.tmpl
 new file mode 100644
 index 0000000..0c40add
@@ -692,7 +690,7 @@ index 0000000..0c40add
 +
 +</book>
 diff --git a/fs/proc/array.c b/fs/proc/array.c
-index 9b45ee8..496fef3 100644
+index 3a1dafd..f0c0ea2 100644
 --- a/fs/proc/array.c
 +++ b/fs/proc/array.c
 @@ -81,6 +81,7 @@
@@ -713,10 +711,10 @@ index 9b45ee8..496fef3 100644
  	if (p->files)
  		fdt = files_fdtable(p->files);
 diff --git a/include/linux/sched.h b/include/linux/sched.h
-index a837b20..b87de83 100644
+index 20b03bf..c6d79af 100644
 --- a/include/linux/sched.h
 +++ b/include/linux/sched.h
-@@ -1397,6 +1397,11 @@ struct task_struct {
+@@ -1406,6 +1406,11 @@ struct task_struct {
  #endif
  	seccomp_t seccomp;
  
@@ -728,235 +726,6 @@ index a837b20..b87de83 100644
  /* Thread group tracking */
     	u32 parent_exec_id;
     	u32 self_exec_id;
-diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
-index e95f523..7d7bdde 100644
---- a/include/linux/tracehook.h
-+++ b/include/linux/tracehook.h
-@@ -49,6 +49,7 @@
- #include <linux/sched.h>
- #include <linux/ptrace.h>
- #include <linux/security.h>
-+#include <linux/utrace.h>
- struct linux_binprm;
- 
- /**
-@@ -63,6 +64,8 @@ struct linux_binprm;
-  */
- static inline int tracehook_expect_breakpoints(struct task_struct *task)
- {
-+	if (unlikely(task_utrace_flags(task) & UTRACE_EVENT(SIGNAL_CORE)))
-+		return 1;
- 	return (task_ptrace(task) & PT_PTRACED) != 0;
- }
- 
-@@ -111,6 +114,9 @@ static inline void ptrace_report_syscall(struct pt_regs *regs)
- static inline __must_check int tracehook_report_syscall_entry(
- 	struct pt_regs *regs)
- {
-+	if ((task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_ENTRY)) &&
-+	    utrace_report_syscall_entry(regs))
-+		return 1;
- 	ptrace_report_syscall(regs);
- 	return 0;
- }
-@@ -134,6 +140,9 @@ static inline __must_check int tracehook_report_syscall_entry(
-  */
- static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
- {
-+	if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT))
-+		utrace_report_syscall_exit(regs);
-+
- 	if (step) {
- 		siginfo_t info;
- 		user_single_step_siginfo(current, regs, &info);
-@@ -201,6 +210,8 @@ static inline void tracehook_report_exec(struct linux_binfmt *fmt,
- 					 struct linux_binprm *bprm,
- 					 struct pt_regs *regs)
- {
-+	if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(EXEC)))
-+		utrace_report_exec(fmt, bprm, regs);
- 	if (!ptrace_event(PT_TRACE_EXEC, PTRACE_EVENT_EXEC, 0) &&
- 	    unlikely(task_ptrace(current) & PT_PTRACED))
- 		send_sig(SIGTRAP, current, 0);
-@@ -218,10 +229,37 @@ static inline void tracehook_report_exec(struct linux_binfmt *fmt,
-  */
- static inline void tracehook_report_exit(long *exit_code)
- {
-+	if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(EXIT)))
-+		utrace_report_exit(exit_code);
- 	ptrace_event(PT_TRACE_EXIT, PTRACE_EVENT_EXIT, *exit_code);
- }
- 
- /**
-+ * tracehook_init_task - task_struct has just been copied
-+ * @task:		new &struct task_struct just copied from parent
-+ *
-+ * Called from do_fork() when @task has just been duplicated.
-+ * After this, @task will be passed to tracehook_free_task()
-+ * even if the rest of its setup fails before it is fully created.
-+ */
-+static inline void tracehook_init_task(struct task_struct *task)
-+{
-+	utrace_init_task(task);
-+}
-+
-+/**
-+ * tracehook_free_task - task_struct is being freed
-+ * @task:		dead &struct task_struct being freed
-+ *
-+ * Called from free_task() when @task is no longer in use.
-+ */
-+static inline void tracehook_free_task(struct task_struct *task)
-+{
-+	if (task_utrace_struct(task))
-+		utrace_free_task(task);
-+}
-+
-+/**
-  * tracehook_prepare_clone - prepare for new child to be cloned
-  * @clone_flags:	%CLONE_* flags from clone/fork/vfork system call
-  *
-@@ -285,6 +323,8 @@ static inline void tracehook_report_clone(struct pt_regs *regs,
- 					  unsigned long clone_flags,
- 					  pid_t pid, struct task_struct *child)
- {
-+	if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(CLONE)))
-+		utrace_report_clone(clone_flags, child);
- 	if (unlikely(task_ptrace(child))) {
- 		/*
- 		 * It doesn't matter who attached/attaching to this
-@@ -317,6 +357,9 @@ static inline void tracehook_report_clone_complete(int trace,
- 						   pid_t pid,
- 						   struct task_struct *child)
- {
-+	if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(CLONE)) &&
-+	    (clone_flags & CLONE_VFORK))
-+		utrace_finish_vfork(current);
- 	if (unlikely(trace))
- 		ptrace_event(0, trace, pid);
- }
-@@ -351,6 +394,10 @@ static inline void tracehook_report_vfork_done(struct task_struct *child,
-  */
- static inline void tracehook_prepare_release_task(struct task_struct *task)
- {
-+	/* see utrace_add_engine() about this barrier */
-+	smp_mb();
-+	if (task_utrace_flags(task))
-+		utrace_maybe_reap(task, task_utrace_struct(task), true);
- }
- 
- /**
-@@ -365,6 +412,7 @@ static inline void tracehook_prepare_release_task(struct task_struct *task)
- static inline void tracehook_finish_release_task(struct task_struct *task)
- {
- 	ptrace_release_task(task);
-+	BUG_ON(task->exit_state != EXIT_DEAD);
- }
- 
- /**
-@@ -386,6 +434,8 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
- 					    const struct k_sigaction *ka,
- 					    struct pt_regs *regs, int stepping)
- {
-+	if (task_utrace_flags(current))
-+		utrace_signal_handler(current, stepping);
- 	if (stepping)
- 		ptrace_notify(SIGTRAP);
- }
-@@ -403,6 +453,8 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
- static inline int tracehook_consider_ignored_signal(struct task_struct *task,
- 						    int sig)
- {
-+	if (unlikely(task_utrace_flags(task) & UTRACE_EVENT(SIGNAL_IGN)))
-+		return 1;
- 	return (task_ptrace(task) & PT_PTRACED) != 0;
- }
- 
-@@ -422,6 +474,9 @@ static inline int tracehook_consider_ignored_signal(struct task_struct *task,
- static inline int tracehook_consider_fatal_signal(struct task_struct *task,
- 						  int sig)
- {
-+	if (unlikely(task_utrace_flags(task) & (UTRACE_EVENT(SIGNAL_TERM) |
-+						UTRACE_EVENT(SIGNAL_CORE))))
-+		return 1;
- 	return (task_ptrace(task) & PT_PTRACED) != 0;
- }
- 
-@@ -436,6 +491,8 @@ static inline int tracehook_consider_fatal_signal(struct task_struct *task,
-  */
- static inline int tracehook_force_sigpending(void)
- {
-+	if (unlikely(task_utrace_flags(current)))
-+		return utrace_interrupt_pending();
- 	return 0;
- }
- 
-@@ -465,6 +522,8 @@ static inline int tracehook_get_signal(struct task_struct *task,
- 				       siginfo_t *info,
- 				       struct k_sigaction *return_ka)
- {
-+	if (unlikely(task_utrace_flags(task)))
-+		return utrace_get_signal(task, regs, info, return_ka);
- 	return 0;
- }
- 
-@@ -475,6 +534,8 @@ static inline int tracehook_get_signal(struct task_struct *task,
-  */
- static inline void tracehook_finish_jctl(void)
- {
-+	if (task_utrace_flags(current))
-+		utrace_finish_stop();
- }
- 
- #define DEATH_REAP			-1
-@@ -497,6 +558,8 @@ static inline void tracehook_finish_jctl(void)
- static inline int tracehook_notify_death(struct task_struct *task,
- 					 void **death_cookie, int group_dead)
- {
-+	*death_cookie = task_utrace_struct(task);
-+
- 	if (task_detached(task))
- 		return task->ptrace ? SIGCHLD : DEATH_REAP;
- 
-@@ -533,6 +596,15 @@ static inline void tracehook_report_death(struct task_struct *task,
- 					  int signal, void *death_cookie,
- 					  int group_dead)
- {
-+	/*
-+	 * If utrace_set_events() was just called to enable
-+	 * UTRACE_EVENT(DEATH), then we are obliged to call
-+	 * utrace_report_death() and not miss it.  utrace_set_events()
-+	 * checks @task->exit_state under tasklist_lock to synchronize
-+	 * with exit_notify(), the caller.
-+	 */
-+	if (task_utrace_flags(task) & _UTRACE_DEATH_EVENTS)
-+		utrace_report_death(task, death_cookie, group_dead, signal);
- }
- 
- #ifdef TIF_NOTIFY_RESUME
-@@ -562,10 +634,21 @@ static inline void set_notify_resume(struct task_struct *task)
-  * asynchronously, this will be called again before we return to
-  * user mode.
-  *
-- * Called without locks.
-+ * Called without locks.  However, on some machines this may be
-+ * called with interrupts disabled.
-  */
- static inline void tracehook_notify_resume(struct pt_regs *regs)
- {
-+	struct task_struct *task = current;
-+	/*
-+	 * Prevent the following store/load from getting ahead of the
-+	 * caller which clears TIF_NOTIFY_RESUME. This pairs with the
-+	 * implicit mb() before setting TIF_NOTIFY_RESUME in
-+	 * set_notify_resume().
-+	 */
-+	smp_mb();
-+	if (task_utrace_flags(task))
-+		utrace_resume(task, regs);
- }
- #endif	/* TIF_NOTIFY_RESUME */
- 
 diff --git a/include/linux/utrace.h b/include/linux/utrace.h
 new file mode 100644
 index 0000000..f251efe
@@ -1656,7 +1425,7 @@ index 0000000..f251efe
 +
 +#endif	/* linux/utrace.h */
 diff --git a/init/Kconfig b/init/Kconfig
-index 412c21b..a03ae51 100644
+index d627783..7afce1f 100644
 --- a/init/Kconfig
 +++ b/init/Kconfig
 @@ -372,6 +372,15 @@ config AUDIT_TREE
@@ -1676,7 +1445,7 @@ index 412c21b..a03ae51 100644
  
  menu "RCU Subsystem"
 diff --git a/kernel/Makefile b/kernel/Makefile
-index 2d64cfc..4a22e81 100644
+index d06467f..85828da 100644
 --- a/kernel/Makefile
 +++ b/kernel/Makefile
 @@ -68,6 +68,7 @@ obj-$(CONFIG_IKCONFIG) += configs.o
@@ -1687,30 +1456,9 @@ index 2d64cfc..4a22e81 100644
  obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
  obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
  obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o
-diff --git a/kernel/fork.c b/kernel/fork.c
-index 0276c30..62caf3d 100644
---- a/kernel/fork.c
-+++ b/kernel/fork.c
-@@ -168,6 +168,7 @@ void free_task(struct task_struct *tsk)
- 	free_thread_info(tsk->stack);
- 	rt_mutex_debug_task_free(tsk);
- 	ftrace_graph_exit_task(tsk);
-+	tracehook_free_task(tsk);
- 	free_task_struct(tsk);
- }
- EXPORT_SYMBOL(free_task);
-@@ -1095,6 +1096,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
- 	if (!p)
- 		goto fork_out;
- 
-+	tracehook_init_task(p);
-+
- 	ftrace_graph_init_task(p);
- 
- 	rt_mutex_init_task(p);
 diff --git a/kernel/utrace.c b/kernel/utrace.c
 new file mode 100644
-index 0000000..f332d65
+index 0000000..ef856c9
 --- /dev/null
 +++ b/kernel/utrace.c
 @@ -0,0 +1,2440 @@
@@ -4000,7 +3748,7 @@ index 0000000..f332d65
 +		spin_lock_irq(&task->sighand->siglock);
 +
 +	if (sig_kernel_stop(signr))
-+		task->group_stop |= GROUP_STOP_DEQUEUED;
++		task->jobctl |= JOBCTL_STOP_DEQUEUED;
 +
 +	return signr;
 +}
@@ -4157,156 +3905,943 @@ index 0000000..f332d65
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:09 2011
+
+From davej  Wed Aug  3 15:16:13 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:09 -0400 (EDT)
-Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO
- zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:01 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:13 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
+ zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:15:37 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id A1FB8D89A7;
-	Sun,  7 Aug 2011 15:18:01 -0400 (EDT)
-Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id JtiDMxvrW-Di; Sun,  7 Aug 2011 15:18:01 -0400 (EDT)
-Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
-	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 7F0E6D8988;
-	Sun,  7 Aug 2011 15:18:01 -0400 (EDT)
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 419B39D8CF;
+	Wed,  3 Aug 2011 15:12:11 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id AmaThyCcp1K4; Wed,  3 Aug 2011 15:12:11 -0400 (EDT)
+Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 2A0B29CE59;
+	Wed,  3 Aug 2011 15:12:11 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JHxlJ027726;
-	Sun, 7 Aug 2011 15:17:59 -0400
+	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JC3DW023262;
+	Wed, 3 Aug 2011 15:12:04 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:23 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:21 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:09:31 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:29 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 02/22] utrace: remove jobctl bits
-Message-ID: <20110807191521.GA14373 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 02/31] utrace: add utrace_init_task/utrace_free_task calls
+Message-ID: <20110803190929.GA30907 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
 Status: RO
-Content-Length: 1889
-Lines: 55
+Content-Length: 1295
+Lines: 47
 
-- change utrace_get_signal() to check GROUP_STOP_PENDING instead of
-  signal->group_stop_count. With the recent changes group_stop_count
-  doesn't necessarily mean this task should participate in group stop.
+Add the necessary copy_process()->utrace_init_task() and
+free_task()->utrace_free_task() calls.
 
-- remove the "participate in group stop" code from utrace_wakeup() and
-  utrace_stop(), this is no longer needed and wrong.
+Originally this was the part of "utrace core" patch, but since
+tracehooks are dying it doesn't make sense to reintroduce them.
+Instead, just call the utrace_ helpers directly. This is fine
+even without CONFIG_UTRACE, gcc is smart enough to optimize out
+the code in free_task().
 
 Signed-off-by: Oleg Nesterov <oleg at redhat.com>
 ---
- kernel/utrace.c |   16 ++--------------
- 1 files changed, 2 insertions(+), 14 deletions(-)
+ kernel/fork.c |    5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
 
-diff --git a/kernel/utrace.c b/kernel/utrace.c
-index f332d65..6e7fafb 100644
---- a/kernel/utrace.c
-+++ b/kernel/utrace.c
-@@ -648,11 +648,7 @@ static void utrace_wakeup(struct task_struct *target, struct utrace *utrace)
- {
- 	lockdep_assert_held(&utrace->lock);
- 	spin_lock_irq(&target->sighand->siglock);
--	if (target->signal->flags & SIGNAL_STOP_STOPPED ||
--	    target->signal->group_stop_count)
--		target->state = TASK_STOPPED;
--	else
--		wake_up_state(target, __TASK_TRACED);
-+	wake_up_state(target, __TASK_TRACED);
- 	spin_unlock_irq(&target->sighand->siglock);
- }
- 
-@@ -805,14 +801,6 @@ relock:
+diff --git a/kernel/fork.c b/kernel/fork.c
+index e7ceaca..a9891da 100644
+--- a/kernel/fork.c
++++ b/kernel/fork.c
+@@ -66,6 +66,7 @@
+ #include <linux/user-return-notifier.h>
+ #include <linux/oom.h>
+ #include <linux/khugepaged.h>
++#include <linux/utrace.h>
  
- 	__set_current_state(TASK_TRACED);
+ #include <asm/pgtable.h>
+ #include <asm/pgalloc.h>
+@@ -167,6 +168,8 @@ void free_task(struct task_struct *tsk)
+ 	free_thread_info(tsk->stack);
+ 	rt_mutex_debug_task_free(tsk);
+ 	ftrace_graph_exit_task(tsk);
++	if (task_utrace_struct(tsk))
++		utrace_free_task(tsk);
+ 	free_task_struct(tsk);
+ }
+ EXPORT_SYMBOL(free_task);
+@@ -1096,6 +1099,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
+ 	if (!p)
+ 		goto fork_out;
  
--	/*
--	 * If there is a group stop in progress,
--	 * we must participate in the bookkeeping.
--	 */
--	if (unlikely(task->signal->group_stop_count) &&
--			!--task->signal->group_stop_count)
--		task->signal->flags = SIGNAL_STOP_STOPPED;
--
- 	spin_unlock_irq(&task->sighand->siglock);
- 	spin_unlock(&utrace->lock);
++	utrace_init_task(p);
++
+ 	ftrace_graph_init_task(p);
  
-@@ -2036,7 +2024,7 @@ int utrace_get_signal(struct task_struct *task, struct pt_regs *regs,
- 		ka = NULL;
- 		memset(return_ka, 0, sizeof *return_ka);
- 	} else if (!(task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) ||
--		   unlikely(task->signal->group_stop_count)) {
-+		   unlikely(task->group_stop & GROUP_STOP_PENDING)) {
- 		/*
- 		 * If no engine is interested in intercepting signals or
- 		 * we must stop, let the caller just dequeue them normally
+ 	rt_mutex_init_task(p);
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:10 2011
+
+From davej  Wed Aug  3 15:16:18 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:10 -0400 (EDT)
-Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO
- zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:04 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:18 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
+ zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:07 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 473EDD89A7;
-	Sun,  7 Aug 2011 15:18:04 -0400 (EDT)
-Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id uA3eVmUnKFQu; Sun,  7 Aug 2011 15:18:04 -0400 (EDT)
-Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
-	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 29079D8988;
-	Sun,  7 Aug 2011 15:18:04 -0400 (EDT)
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id F28379DE70;
+	Wed,  3 Aug 2011 15:12:13 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id p92IDp0LZ5jX; Wed,  3 Aug 2011 15:12:13 -0400 (EDT)
+Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id D4E339DE68;
+	Wed,  3 Aug 2011 15:12:13 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JI1LH027738;
-	Sun, 7 Aug 2011 15:18:02 -0400
+	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JC6IA023283;
+	Wed, 3 Aug 2011 15:12:07 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:25 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:23 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:09:34 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:32 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 03/22] ptrace: take ->siglock around s/TRACED/RUNNING/
-Message-ID: <20110807191523.GA14376 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 03/31] tracehooks: add utrace hooks
+Message-ID: <20110803190932.GA30915 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
 Status: RO
-Content-Length: 1623
-Lines: 55
+Content-Length: 2310
+Lines: 75
 
-change ptrace_resume() and ptrace_stop() to take ->siglock around changing
-task->state from TRACED to RUNNING.
+Add the necessary utrace hooks in the tracehooks which were not
+removed yet.
 
-With this patch __TASK_TRACED/STOPPED bits are fully protected by ->siglock,
+Signed-off-by: Oleg Nesterov <oleg at redhat.com>
+---
+ include/linux/tracehook.h |   22 +++++++++++++++++++++-
+ 1 files changed, 21 insertions(+), 1 deletions(-)
+
+diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
+index a71a292..8cc28bc 100644
+--- a/include/linux/tracehook.h
++++ b/include/linux/tracehook.h
+@@ -49,6 +49,7 @@
+ #include <linux/sched.h>
+ #include <linux/ptrace.h>
+ #include <linux/security.h>
++#include <linux/utrace.h>
+ struct linux_binprm;
+ 
+ /*
+@@ -96,6 +97,9 @@ static inline void ptrace_report_syscall(struct pt_regs *regs)
+ static inline __must_check int tracehook_report_syscall_entry(
+ 	struct pt_regs *regs)
+ {
++	if ((task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_ENTRY)) &&
++	    utrace_report_syscall_entry(regs))
++		return 1;
+ 	ptrace_report_syscall(regs);
+ 	return 0;
+ }
+@@ -119,6 +123,9 @@ static inline __must_check int tracehook_report_syscall_entry(
+  */
+ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
+ {
++	if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT))
++		utrace_report_syscall_exit(regs);
++
+ 	if (step) {
+ 		siginfo_t info;
+ 		user_single_step_siginfo(current, regs, &info);
+@@ -148,6 +155,8 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
+ 					    const struct k_sigaction *ka,
+ 					    struct pt_regs *regs, int stepping)
+ {
++	if (task_utrace_flags(current))
++		utrace_signal_handler(current, stepping);
+ 	if (stepping)
+ 		ptrace_notify(SIGTRAP);
+ }
+@@ -179,10 +188,21 @@ static inline void set_notify_resume(struct task_struct *task)
+  * asynchronously, this will be called again before we return to
+  * user mode.
+  *
+- * Called without locks.
++ * Called without locks.  However, on some machines this may be
++ * called with interrupts disabled.
+  */
+ static inline void tracehook_notify_resume(struct pt_regs *regs)
+ {
++	struct task_struct *task = current;
++	/*
++	 * Prevent the following store/load from getting ahead of the
++	 * caller which clears TIF_NOTIFY_RESUME. This pairs with the
++	 * implicit mb() before setting TIF_NOTIFY_RESUME in
++	 * set_notify_resume().
++	 */
++	smp_mb();
++	if (task_utrace_flags(task))
++		utrace_resume(task, regs);
+ }
+ #endif	/* TIF_NOTIFY_RESUME */
+ 
+-- 
+1.5.5.1
+
+
+From davej  Wed Aug  3 15:16:14 2011
+Return-Path: oleg at redhat.com
+X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
+	gelk.kernelslacker.org
+X-Spam-Level: 
+X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
+	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
+Received: from mail.corp.redhat.com [10.5.5.52]
+	by gelk with IMAP (fetchmail-6.3.20)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:14 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
+ zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:15:37 -0400 (EDT)
+Received: from localhost (localhost.localdomain [127.0.0.1])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 92FCA9D8FA;
+	Wed,  3 Aug 2011 15:12:16 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id lQaZCHUpw8DT; Wed,  3 Aug 2011 15:12:16 -0400 (EDT)
+Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 7479B9D8C9;
+	Wed,  3 Aug 2011 15:12:16 -0400 (EDT)
+Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
+	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JC91G023308;
+	Wed, 3 Aug 2011 15:12:09 -0400
+Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
+	oleg at redhat.com; Wed,  3 Aug 2011 21:09:37 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:35 +0200
+From: Oleg Nesterov <oleg at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 04/31] tracehooks: reintroduce
+	tracehook_consider_fatal_signal()
+Message-ID: <20110803190935.GA30918 at redhat.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
+User-Agent: Mutt/1.5.18 (2008-05-17)
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
+Status: RO
+Content-Length: 3257
+Lines: 90
+
+Add the killed tracehook_consider_fatal_signal() back. It has multiple
+callers and it is not easy add the necessary checks inline.
+
+Signed-off-by: Oleg Nesterov <oleg at redhat.com>
+---
+ arch/s390/kernel/traps.c  |    4 ++--
+ include/linux/tracehook.h |   22 ++++++++++++++++++++++
+ kernel/signal.c           |    4 ++--
+ 3 files changed, 26 insertions(+), 4 deletions(-)
+
+diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
+index ffabcd9..1018ab6 100644
+--- a/arch/s390/kernel/traps.c
++++ b/arch/s390/kernel/traps.c
+@@ -329,7 +329,7 @@ void __kprobes do_per_trap(struct pt_regs *regs)
+ 
+ 	if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, SIGTRAP) == NOTIFY_STOP)
+ 		return;
+-	if (!current->ptrace)
++	if (!tracehook_consider_fatal_signal(current, SIGTRAP))
+ 		return;
+ 	info.si_signo = SIGTRAP;
+ 	info.si_errno = 0;
+@@ -428,7 +428,7 @@ static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code,
+ 		if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
+ 			return;
+ 		if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
+-			if (current->ptrace) {
++			if (tracehook_consider_fatal_signal(current, SIGTRAP)) {
+ 				info.si_signo = SIGTRAP;
+ 				info.si_errno = 0;
+ 				info.si_code = TRAP_BRKPT;
+diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
+index 8cc28bc..ec2af67 100644
+--- a/include/linux/tracehook.h
++++ b/include/linux/tracehook.h
+@@ -161,6 +161,28 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
+ 		ptrace_notify(SIGTRAP);
+ }
+ 
++/**
++ * tracehook_consider_fatal_signal - suppress special handling of fatal signal
++ * @task:		task receiving the signal
++ * @sig:		signal number being sent
++ *
++ * Return nonzero to prevent special handling of this termination signal.
++ * Normally handler for signal is %SIG_DFL.  It can be %SIG_IGN if @sig is
++ * ignored, in which case force_sig() is about to reset it to %SIG_DFL.
++ * When this returns zero, this signal might cause a quick termination
++ * that does not give the debugger a chance to intercept the signal.
++ *
++ * Called with or without @task->sighand->siglock held.
++ */
++static inline int tracehook_consider_fatal_signal(struct task_struct *task,
++						  int sig)
++{
++	if (unlikely(task_utrace_flags(task) & (UTRACE_EVENT(SIGNAL_TERM) |
++						UTRACE_EVENT(SIGNAL_CORE))))
++		return 1;
++	return task->ptrace != 0;
++}
++
+ #ifdef TIF_NOTIFY_RESUME
+ /**
+  * set_notify_resume - cause tracehook_notify_resume() to be called
+diff --git a/kernel/signal.c b/kernel/signal.c
+index 291c970..d7ef0da 100644
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -494,7 +494,7 @@ int unhandled_signal(struct task_struct *tsk, int sig)
+ 	if (handler != SIG_IGN && handler != SIG_DFL)
+ 		return 0;
+ 	/* if ptraced, let the tracer determine */
+-	return !tsk->ptrace;
++	return !tracehook_consider_fatal_signal(tsk, sig);
+ }
+ 
+ /*
+@@ -982,7 +982,7 @@ static void complete_signal(int sig, struct task_struct *p, int group)
+ 	if (sig_fatal(p, sig) &&
+ 	    !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) &&
+ 	    !sigismember(&t->real_blocked, sig) &&
+-	    (sig == SIGKILL || !t->ptrace)) {
++	    (sig == SIGKILL || !tracehook_consider_fatal_signal(t, sig))) {
+ 		/*
+ 		 * This signal will be fatal to the whole group.
+ 		 */
+-- 
+1.5.5.1
+
+
+From davej  Wed Aug  3 15:16:20 2011
+Return-Path: oleg at redhat.com
+X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
+	gelk.kernelslacker.org
+X-Spam-Level: 
+X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
+	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
+Received: from mail.corp.redhat.com [10.5.5.52]
+	by gelk with IMAP (fetchmail-6.3.20)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:20 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
+ zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:08 -0400 (EDT)
+Received: from localhost (localhost.localdomain [127.0.0.1])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 374FE9DE74;
+	Wed,  3 Aug 2011 15:12:19 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id Sun0Twp72xGV; Wed,  3 Aug 2011 15:12:19 -0400 (EDT)
+Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 223E39DD25;
+	Wed,  3 Aug 2011 15:12:19 -0400 (EDT)
+Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
+	by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCBgK008326;
+	Wed, 3 Aug 2011 15:12:12 -0400
+Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
+	oleg at redhat.com; Wed,  3 Aug 2011 21:09:39 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:37 +0200
+From: Oleg Nesterov <oleg at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 05/31] add utrace hooks into sig_ignored() and
+	recalc_sigpending()
+Message-ID: <20110803190937.GA30926 at redhat.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
+User-Agent: Mutt/1.5.18 (2008-05-17)
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22
+Status: RO
+Content-Length: 1508
+Lines: 51
+
+Add the necessary and somewhat "special" hooks into sig_ignored() and
+recalc_sigpending(). Basically this restores _force_sigpending() and
+_consider_ignored_signal() tracehook logic.
+
+Signed-off-by: Oleg Nesterov <oleg at redhat.com>
+---
+ include/linux/utrace.h |    2 ++
+ kernel/signal.c        |    7 ++++++-
+ 2 files changed, 8 insertions(+), 1 deletions(-)
+
+diff --git a/include/linux/utrace.h b/include/linux/utrace.h
+index f251efe..1b8da1c 100644
+--- a/include/linux/utrace.h
++++ b/include/linux/utrace.h
+@@ -107,6 +107,8 @@ bool utrace_report_syscall_entry(struct pt_regs *);
+ void utrace_report_syscall_exit(struct pt_regs *);
+ void utrace_signal_handler(struct task_struct *, int);
+ 
++#define UTRACE_FLAG(task, ev)	(task_utrace_flags(task) & UTRACE_EVENT(ev))
++
+ #ifndef CONFIG_UTRACE
+ 
+ /*
+diff --git a/kernel/signal.c b/kernel/signal.c
+index d7ef0da..0f9af0b 100644
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -87,7 +87,7 @@ static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns)
+ 	/*
+ 	 * Tracers may want to know about even ignored signals.
+ 	 */
+-	return !t->ptrace;
++	return !t->ptrace && !UTRACE_FLAG(t, SIGNAL_IGN);
+ }
+ 
+ /*
+@@ -150,6 +150,11 @@ void recalc_sigpending_and_wake(struct task_struct *t)
+ 
+ void recalc_sigpending(void)
+ {
++	if (task_utrace_flags(current) && utrace_interrupt_pending()) {
++		set_thread_flag(TIF_SIGPENDING);
++		return;
++	}
++
+ 	if (!recalc_sigpending_tsk(current) && !freezing(current))
+ 		clear_thread_flag(TIF_SIGPENDING);
+ 
+-- 
+1.5.5.1
+
+
+From davej  Wed Aug  3 15:16:21 2011
+Return-Path: oleg at redhat.com
+X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
+	gelk.kernelslacker.org
+X-Spam-Level: 
+X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
+	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
+Received: from mail.corp.redhat.com [10.5.5.52]
+	by gelk with IMAP (fetchmail-6.3.20)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:21 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
+ zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:09 -0400 (EDT)
+Received: from localhost (localhost.localdomain [127.0.0.1])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 054279DE7D;
+	Wed,  3 Aug 2011 15:12:22 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id 1BosZIzYSIW0; Wed,  3 Aug 2011 15:12:21 -0400 (EDT)
+Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id E41DC9DE7B;
+	Wed,  3 Aug 2011 15:12:21 -0400 (EDT)
+Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
+	by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p73JCEgD022264;
+	Wed, 3 Aug 2011 15:12:15 -0400
+Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
+	oleg at redhat.com; Wed,  3 Aug 2011 21:09:42 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:40 +0200
+From: Oleg Nesterov <oleg at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 06/31] restore the EXEC/EXIT/CLONE utrace hooks
+Message-ID: <20110803190940.GA30929 at redhat.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
+User-Agent: Mutt/1.5.18 (2008-05-17)
+X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12
+Status: RO
+Content-Length: 2383
+Lines: 83
+
+Restore the "trivial" EXEC/EXIT/CLONE utrace hooks. Add the
+simple helper, UTRACE_HOOK(), to minimize the changes.
+
+Signed-off-by: Oleg Nesterov <oleg at redhat.com>
+---
+ fs/exec.c              |    5 ++++-
+ include/linux/utrace.h |    6 ++++++
+ kernel/exit.c          |    1 +
+ kernel/fork.c          |    4 ++++
+ 4 files changed, 15 insertions(+), 1 deletions(-)
+
+diff --git a/fs/exec.c b/fs/exec.c
+index da80612..a0814cd 100644
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -1401,9 +1401,12 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
+ 			 */
+ 			bprm->recursion_depth = depth;
+ 			if (retval >= 0) {
+-				if (depth == 0)
++				if (depth == 0) {
++					UTRACE_HOOK(current, EXEC,
++						report_exec(fmt, bprm, regs));
+ 					ptrace_event(PTRACE_EVENT_EXEC,
+ 							old_pid);
++				}
+ 				put_binfmt(fmt);
+ 				allow_write_access(bprm->file);
+ 				if (bprm->file)
+diff --git a/include/linux/utrace.h b/include/linux/utrace.h
+index 1b8da1c..9ac0b1b 100644
+--- a/include/linux/utrace.h
++++ b/include/linux/utrace.h
+@@ -109,6 +109,12 @@ void utrace_signal_handler(struct task_struct *, int);
+ 
+ #define UTRACE_FLAG(task, ev)	(task_utrace_flags(task) & UTRACE_EVENT(ev))
+ 
++#define UTRACE_HOOK(task, ev, callback)			\
++	do {						\
++		if (UTRACE_FLAG(task, ev))		\
++			utrace_ ## callback;		\
++	} while (0)
++
+ #ifndef CONFIG_UTRACE
+ 
+ /*
+diff --git a/kernel/exit.c b/kernel/exit.c
+index 2913b35..c1b0ab6 100644
+--- a/kernel/exit.c
++++ b/kernel/exit.c
+@@ -913,6 +913,7 @@ NORET_TYPE void do_exit(long code)
+ 	 */
+ 	set_fs(USER_DS);
+ 
++	UTRACE_HOOK(current, EXIT, report_exit(&code));
+ 	ptrace_event(PTRACE_EVENT_EXIT, code);
+ 
+ 	validate_creds_for_do_exit(tsk);
+diff --git a/kernel/fork.c b/kernel/fork.c
+index a9891da..37f4a07 100644
+--- a/kernel/fork.c
++++ b/kernel/fork.c
+@@ -1539,6 +1539,8 @@ long do_fork(unsigned long clone_flags,
+ 
+ 		audit_finish_fork(p);
+ 
++		UTRACE_HOOK(current, CLONE, report_clone(clone_flags, p));
++
+ 		/*
+ 		 * We set PF_STARTING at creation in case tracing wants to
+ 		 * use this to distinguish a fully live task from one that
+@@ -1550,6 +1552,8 @@ long do_fork(unsigned long clone_flags,
+ 		wake_up_new_task(p);
+ 
+ 		/* forking complete and child started to run, tell ptracer */
++		if (clone_flags & CLONE_VFORK)
++			UTRACE_HOOK(current, CLONE, finish_vfork(current));
+ 		if (unlikely(trace))
+ 			ptrace_event(trace, nr);
+ 
+-- 
+1.5.5.1
+
+
+From davej  Wed Aug  3 15:16:23 2011
+Return-Path: oleg at redhat.com
+X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
+	gelk.kernelslacker.org
+X-Spam-Level: 
+X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
+	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
+Received: from mail.corp.redhat.com [10.5.5.52]
+	by gelk with IMAP (fetchmail-6.3.20)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:23 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
+ zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:13 -0400 (EDT)
+Received: from localhost (localhost.localdomain [127.0.0.1])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id B36EC9DE82;
+	Wed,  3 Aug 2011 15:12:24 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id 7Qqv+lXfqHw6; Wed,  3 Aug 2011 15:12:24 -0400 (EDT)
+Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 9F8AF9DD25;
+	Wed,  3 Aug 2011 15:12:24 -0400 (EDT)
+Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
+	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCH0U023349;
+	Wed, 3 Aug 2011 15:12:17 -0400
+Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
+	oleg at redhat.com; Wed,  3 Aug 2011 21:09:45 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:43 +0200
+From: Oleg Nesterov <oleg at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 07/31] utrace: utrace_report_death() can use
+	task_utrace_struct()
+Message-ID: <20110803190943.GA30936 at redhat.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
+User-Agent: Mutt/1.5.18 (2008-05-17)
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
+Status: RO
+Content-Length: 1692
+Lines: 44
+
+utrace_report_death() assumes that the caller (exit_notify) should
+pass task->utrace as an argument. This is no longer needed, it can
+safely do task_utrace_struct(). This way we avoid the nasty changes
+in exit_notify().
+
+Signed-off-by: Oleg Nesterov <oleg at redhat.com>
+---
+ include/linux/utrace.h |    2 +-
+ kernel/utrace.c        |    5 +++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/include/linux/utrace.h b/include/linux/utrace.h
+index 9ac0b1b..9a2e2f4 100644
+--- a/include/linux/utrace.h
++++ b/include/linux/utrace.h
+@@ -99,7 +99,7 @@ int utrace_get_signal(struct task_struct *, struct pt_regs *,
+ void utrace_report_clone(unsigned long, struct task_struct *);
+ void utrace_finish_vfork(struct task_struct *);
+ void utrace_report_exit(long *exit_code);
+-void utrace_report_death(struct task_struct *, struct utrace *, bool, int);
++void utrace_report_death(struct task_struct *, bool, int);
+ void utrace_report_jctl(int notify, int type);
+ void utrace_report_exec(struct linux_binfmt *, struct linux_binprm *,
+ 			struct pt_regs *regs);
+diff --git a/kernel/utrace.c b/kernel/utrace.c
+index ef856c9..1e750ad 100644
+--- a/kernel/utrace.c
++++ b/kernel/utrace.c
+@@ -1759,9 +1759,10 @@ void utrace_report_exit(long *exit_code)
+  * For this reason, utrace_release_task checks for the event bits that get
+  * us here, and delays its cleanup for us to do.
+  */
+-void utrace_report_death(struct task_struct *task, struct utrace *utrace,
+-			 bool group_dead, int signal)
++void utrace_report_death(struct task_struct *task, bool group_dead, int signal)
+ {
++	struct utrace *utrace = task_utrace_struct(task);
++
+ 	INIT_REPORT(report);
+ 
+ 	BUG_ON(!task->exit_state);
+-- 
+1.5.5.1
+
+
+From davej  Wed Aug  3 15:16:15 2011
+Return-Path: oleg at redhat.com
+X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
+	gelk.kernelslacker.org
+X-Spam-Level: 
+X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
+	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
+Received: from mail.corp.redhat.com [10.5.5.52]
+	by gelk with IMAP (fetchmail-6.3.20)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:15 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
+ zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:15:39 -0400 (EDT)
+Received: from localhost (localhost.localdomain [127.0.0.1])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 76DA49D9C7;
+	Wed,  3 Aug 2011 15:12:27 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id 25xHJjCTouA4; Wed,  3 Aug 2011 15:12:27 -0400 (EDT)
+Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 490E79D9AB;
+	Wed,  3 Aug 2011 15:12:27 -0400 (EDT)
+Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
+	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCKXo023360;
+	Wed, 3 Aug 2011 15:12:20 -0400
+Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
+	oleg at redhat.com; Wed,  3 Aug 2011 21:09:47 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:45 +0200
+From: Oleg Nesterov <oleg at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 08/31] restore the DEATH/REAP utrace hooks
+Message-ID: <20110803190945.GA30939 at redhat.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
+User-Agent: Mutt/1.5.18 (2008-05-17)
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
+Status: RO
+Content-Length: 2346
+Lines: 70
+
+Restore the necessary hooks in release_task() and exit_notify(),
+add the corresponding helpers into utrace.h.
+
+Note: the @signal argument passed to ->report_death() does not
+match the previous behaviour. I think this shouldn't affect the
+current users, and I bet nobody can really understand what this
+magic argument should actually mean anyway.
+
+Signed-off-by: Oleg Nesterov <oleg at redhat.com>
+---
+ include/linux/utrace.h |   22 ++++++++++++++++++++++
+ kernel/exit.c          |    4 ++++
+ 2 files changed, 26 insertions(+), 0 deletions(-)
+
+diff --git a/include/linux/utrace.h b/include/linux/utrace.h
+index 9a2e2f4..cf13839 100644
+--- a/include/linux/utrace.h
++++ b/include/linux/utrace.h
+@@ -697,4 +697,26 @@ static inline __must_check int utrace_barrier_pid(struct pid *pid,
+ 
+ #endif	/* CONFIG_UTRACE */
+ 
++static inline void utrace_release_task(struct task_struct *task)
++{
++	/* see utrace_add_engine() about this barrier */
++	smp_mb();
++	if (task_utrace_flags(task))
++		utrace_maybe_reap(task, task_utrace_struct(task), true);
++}
++
++static inline void utrace_exit_notify(struct task_struct *task,
++					  int signal, int group_dead)
++{
++	/*
++	 * If utrace_set_events() was just called to enable
++	 * UTRACE_EVENT(DEATH), then we are obliged to call
++	 * utrace_report_death() and not miss it.  utrace_set_events()
++	 * checks @task->exit_state under tasklist_lock to synchronize
++	 * with exit_notify(), the caller.
++	 */
++	if (task_utrace_flags(task) & _UTRACE_DEATH_EVENTS)
++		utrace_report_death(task, group_dead, signal);
++}
++
+ #endif	/* linux/utrace.h */
+diff --git a/kernel/exit.c b/kernel/exit.c
+index c1b0ab6..ba5ba22 100644
+--- a/kernel/exit.c
++++ b/kernel/exit.c
+@@ -168,6 +168,8 @@ void release_task(struct task_struct * p)
+ 	struct task_struct *leader;
+ 	int zap_leader;
+ repeat:
++	utrace_release_task(p);
++
+ 	/* don't need to get the RCU readlock here - the process is dead and
+ 	 * can't be modifying its own credentials. But shut RCU-lockdep up */
+ 	rcu_read_lock();
+@@ -860,6 +862,8 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
+ 		wake_up_process(tsk->signal->group_exit_task);
+ 	write_unlock_irq(&tasklist_lock);
+ 
++	utrace_exit_notify(tsk, autoreap ? -1 : SIGCHLD, group_dead);
++
+ 	/* If the process is dead, release it - nobody will wait for it */
+ 	if (autoreap)
+ 		release_task(tsk);
+-- 
+1.5.5.1
+
+
+From davej  Wed Aug  3 15:22:02 2011
+Return-Path: oleg at redhat.com
+X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
+	gelk.kernelslacker.org
+X-Spam-Level: 
+X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
+	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
+Received: from mail.corp.redhat.com [10.5.5.52]
+	by gelk with IMAP (fetchmail-6.3.20)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:22:02 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
+ zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:17:16 -0400 (EDT)
+Received: from localhost (localhost.localdomain [127.0.0.1])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 26DB69DE8C;
+	Wed,  3 Aug 2011 15:12:30 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id DbxGfmFvtTiR; Wed,  3 Aug 2011 15:12:30 -0400 (EDT)
+Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 0A30A9DE91;
+	Wed,  3 Aug 2011 15:12:30 -0400 (EDT)
+Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
+	by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCMDQ008389;
+	Wed, 3 Aug 2011 15:12:23 -0400
+Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
+	oleg at redhat.com; Wed,  3 Aug 2011 21:09:50 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:48 +0200
+From: Oleg Nesterov <oleg at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 09/31] utrace: remove jobctl bits
+Message-ID: <20110803190948.GA30942 at redhat.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
+User-Agent: Mutt/1.5.18 (2008-05-17)
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22
+Status: RO
+Content-Length: 1888
+Lines: 56
+
+- change utrace_get_signal() to check JOBCTL_STOP_PENDING instead of
+  signal->group_stop_count. With the recent changes group_stop_count
+  doesn't necessarily mean this task should participate in group stop.
+
+- remove the "participate in group stop" code from utrace_wakeup() and
+  utrace_stop(), this is no longer needed and wrong.
+
+Signed-off-by: Oleg Nesterov <oleg at redhat.com>
+---
+ kernel/utrace.c |   16 ++--------------
+ 1 files changed, 2 insertions(+), 14 deletions(-)
+
+diff --git a/kernel/utrace.c b/kernel/utrace.c
+index 1e750ad..5d3974e 100644
+--- a/kernel/utrace.c
++++ b/kernel/utrace.c
+@@ -648,11 +648,7 @@ static void utrace_wakeup(struct task_struct *target, struct utrace *utrace)
+ {
+ 	lockdep_assert_held(&utrace->lock);
+ 	spin_lock_irq(&target->sighand->siglock);
+-	if (target->signal->flags & SIGNAL_STOP_STOPPED ||
+-	    target->signal->group_stop_count)
+-		target->state = TASK_STOPPED;
+-	else
+-		wake_up_state(target, __TASK_TRACED);
++	wake_up_state(target, __TASK_TRACED);
+ 	spin_unlock_irq(&target->sighand->siglock);
+ }
+ 
+@@ -805,14 +801,6 @@ relock:
+ 
+ 	__set_current_state(TASK_TRACED);
+ 
+-	/*
+-	 * If there is a group stop in progress,
+-	 * we must participate in the bookkeeping.
+-	 */
+-	if (unlikely(task->signal->group_stop_count) &&
+-			!--task->signal->group_stop_count)
+-		task->signal->flags = SIGNAL_STOP_STOPPED;
+-
+ 	spin_unlock_irq(&task->sighand->siglock);
+ 	spin_unlock(&utrace->lock);
+ 
+@@ -2037,7 +2025,7 @@ int utrace_get_signal(struct task_struct *task, struct pt_regs *regs,
+ 		ka = NULL;
+ 		memset(return_ka, 0, sizeof *return_ka);
+ 	} else if (!(task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) ||
+-		   unlikely(task->signal->group_stop_count)) {
++		   unlikely(task->jobctl & JOBCTL_STOP_PENDING)) {
+ 		/*
+ 		 * If no engine is interested in intercepting signals or
+ 		 * we must stop, let the caller just dequeue them normally
+-- 
+1.5.5.1
+
+
+From davej  Wed Aug  3 15:16:17 2011
+Return-Path: oleg at redhat.com
+X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
+	gelk.kernelslacker.org
+X-Spam-Level: 
+X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
+	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
+Received: from mail.corp.redhat.com [10.5.5.52]
+	by gelk with IMAP (fetchmail-6.3.20)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:17 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
+ zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:15:52 -0400 (EDT)
+Received: from localhost (localhost.localdomain [127.0.0.1])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id AB6E39DA46;
+	Wed,  3 Aug 2011 15:12:32 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id LkzmRGslEelr; Wed,  3 Aug 2011 15:12:32 -0400 (EDT)
+Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 959659DA60;
+	Wed,  3 Aug 2011 15:12:32 -0400 (EDT)
+Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
+	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCPx7023400;
+	Wed, 3 Aug 2011 15:12:25 -0400
+Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
+	oleg at redhat.com; Wed,  3 Aug 2011 21:09:53 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:51 +0200
+From: Oleg Nesterov <oleg at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 10/31] ptrace: take ->siglock around s/TRACED/RUNNING/
+Message-ID: <20110803190951.GA30949 at redhat.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
+User-Agent: Mutt/1.5.18 (2008-05-17)
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
+Status: RO
+Content-Length: 1624
+Lines: 56
+
+change ptrace_resume() and ptrace_stop() to take ->siglock around changing
+task->state from TRACED to RUNNING.
+
+With this patch __TASK_TRACED/STOPPED bits are fully protected by ->siglock,
 nobody can set or clear these bits without ->siglock held.
 
 Signed-off-by: Oleg Nesterov <oleg at redhat.com>
@@ -4316,10 +4851,10 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  2 files changed, 10 insertions(+), 1 deletions(-)
 
 diff --git a/kernel/ptrace.c b/kernel/ptrace.c
-index 2df1157..9988b13 100644
+index 9de3ecf..56b8fc1 100644
 --- a/kernel/ptrace.c
 +++ b/kernel/ptrace.c
-@@ -534,6 +534,8 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)
+@@ -589,6 +589,8 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)
  static int ptrace_resume(struct task_struct *child, long request,
  			 unsigned long data)
  {
@@ -4328,7 +4863,7 @@ index 2df1157..9988b13 100644
  	if (!valid_signal(data))
  		return -EIO;
  
-@@ -562,7 +564,11 @@ static int ptrace_resume(struct task_struct *child, long request,
+@@ -617,7 +619,11 @@ static int ptrace_resume(struct task_struct *child, long request,
  	}
  
  	child->exit_code = data;
@@ -4342,10 +4877,10 @@ index 2df1157..9988b13 100644
  	return 0;
  }
 diff --git a/kernel/signal.c b/kernel/signal.c
-index ff76786..2138cee 100644
+index 0f9af0b..71f5cca 100644
 --- a/kernel/signal.c
 +++ b/kernel/signal.c
-@@ -1799,7 +1799,10 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
+@@ -1878,7 +1878,10 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
  		if (gstop_done)
  			do_notify_parent_cldstop(current, false, why);
  
@@ -4359,50 +4894,51 @@ index ff76786..2138cee 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:11 2011
+
+From davej  Wed Aug  3 15:16:37 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:11 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:37 -0400 (EDT)
 Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
  zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:06 -0400 (EDT)
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:29 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id D76B6A5D58;
-	Sun,  7 Aug 2011 15:18:06 -0400 (EDT)
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 5034E9DEA4;
+	Wed,  3 Aug 2011 15:12:35 -0400 (EDT)
 Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
 	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id xyKeY-zzvTgR; Sun,  7 Aug 2011 15:18:06 -0400 (EDT)
-Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id BB0E49C7FA;
-	Sun,  7 Aug 2011 15:18:06 -0400 (EDT)
+	with ESMTP id 8BhFlmqmXy8l; Wed,  3 Aug 2011 15:12:35 -0400 (EDT)
+Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 31AEE9DEAB;
+	Wed,  3 Aug 2011 15:12:35 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JI4PF028668;
-	Sun, 7 Aug 2011 15:18:05 -0400
+	by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCRCZ008434;
+	Wed, 3 Aug 2011 15:12:28 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:28 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:26 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:09:55 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:53 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 04/22] introduce wake_up_quiescent()
-Message-ID: <20110807191526.GA14383 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 11/31] introduce wake_up_quiescent()
+Message-ID: <20110803190953.GA30952 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22
 Status: RO
-Content-Length: 3103
-Lines: 92
+Content-Length: 3186
+Lines: 93
 
 No functional changes. Add the new helper, wake_up_quiescent(task, state),
 which simply returns wake_up_state(task, state). Change all callers which
@@ -4432,10 +4968,10 @@ index a822300..2be3712 100644
  extern int do_send_sig_info(int sig, struct siginfo *info,
  				struct task_struct *p, bool group);
 diff --git a/kernel/ptrace.c b/kernel/ptrace.c
-index 9988b13..26ae214 100644
+index 56b8fc1..4194664 100644
 --- a/kernel/ptrace.c
 +++ b/kernel/ptrace.c
-@@ -566,7 +566,7 @@ static int ptrace_resume(struct task_struct *child, long request,
+@@ -621,7 +621,7 @@ static int ptrace_resume(struct task_struct *child, long request,
  	child->exit_code = data;
  
  	if (lock_task_sighand(child, &flags)) {
@@ -4445,10 +4981,10 @@ index 9988b13..26ae214 100644
  	}
  
 diff --git a/kernel/signal.c b/kernel/signal.c
-index 2138cee..4fcf1c7 100644
+index 71f5cca..3e8e0b1 100644
 --- a/kernel/signal.c
 +++ b/kernel/signal.c
-@@ -652,6 +652,14 @@ void signal_wake_up(struct task_struct *t, int resume)
+@@ -702,6 +702,14 @@ void signal_wake_up(struct task_struct *t, int resume)
  }
  
  /*
@@ -4463,16 +4999,16 @@ index 2138cee..4fcf1c7 100644
   * Remove signals in mask from the pending set and queue.
   * Returns 1 if any signals were found.
   *
-@@ -811,7 +819,7 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns)
- 		do {
- 			task_clear_group_stop_pending(t);
+@@ -888,7 +896,7 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns)
+ 			task_clear_jobctl_pending(t, JOBCTL_STOP_PENDING);
  			rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending);
--			wake_up_state(t, __TASK_STOPPED);
-+			wake_up_quiescent(t, __TASK_STOPPED);
+ 			if (likely(!(t->ptrace & PT_SEIZED)))
+-				wake_up_state(t, __TASK_STOPPED);
++				wake_up_quiescent(t, __TASK_STOPPED);
+ 			else
+ 				ptrace_trap_notify(t);
  		} while_each_thread(p, t);
- 
- 		/*
-@@ -1800,7 +1808,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
+@@ -1879,7 +1887,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
  			do_notify_parent_cldstop(current, false, why);
  
  		spin_lock_irq(&current->sighand->siglock);
@@ -4482,7 +5018,7 @@ index 2138cee..4fcf1c7 100644
  
  		if (clear_code)
 diff --git a/kernel/utrace.c b/kernel/utrace.c
-index 6e7fafb..d7c547c 100644
+index 5d3974e..cebc390 100644
 --- a/kernel/utrace.c
 +++ b/kernel/utrace.c
 @@ -648,7 +648,7 @@ static void utrace_wakeup(struct task_struct *target, struct utrace *utrace)
@@ -4497,53 +5033,54 @@ index 6e7fafb..d7c547c 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:13 2011
+
+From davej  Wed Aug  3 15:22:01 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:13 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:22:01 -0400 (EDT)
 Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
  zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:09 -0400 (EDT)
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:17:15 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id C8DCF1322A2;
-	Sun,  7 Aug 2011 15:18:09 -0400 (EDT)
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id F2DE19DC07;
+	Wed,  3 Aug 2011 15:12:37 -0400 (EDT)
 Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
 	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id ZQXZL5xrzV21; Sun,  7 Aug 2011 15:18:09 -0400 (EDT)
-Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id B3D6D128FDA;
-	Sun,  7 Aug 2011 15:18:09 -0400 (EDT)
+	with ESMTP id IYfqfx8GhNWc; Wed,  3 Aug 2011 15:12:37 -0400 (EDT)
+Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id D645E9DAF7;
+	Wed,  3 Aug 2011 15:12:37 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p77JI7P5029847;
-	Sun, 7 Aug 2011 15:18:07 -0400
+	by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCUNh008446;
+	Wed, 3 Aug 2011 15:12:31 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:31 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:28 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:09:58 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:56 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 05/22] introduce ptrace_signal_wake_up()
-Message-ID: <20110807191528.GA14386 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 12/31] introduce ptrace_signal_wake_up()
+Message-ID: <20110803190956.GA30959 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22
 Status: RO
-Content-Length: 1974
-Lines: 67
+Content-Length: 3667
+Lines: 113
 
-Add the new helper, ptrace_signal_wake_up(), change ptrace.c to use
-it instead of signal_wake_up().
+Add the new helper, ptrace_signal_wake_up(), change ptrace.c/signal.c
+to use it instead of signal_wake_up() to wake up a STOPPED/TRACED task.
 
 The new helper does almost the same, except:
 
@@ -4563,18 +5100,32 @@ wake_up_quiescent().
 
 Signed-off-by: Oleg Nesterov <oleg at redhat.com>
 ---
- kernel/ptrace.c |   16 ++++++++++++++--
- 1 files changed, 14 insertions(+), 2 deletions(-)
+ include/linux/ptrace.h |    1 +
+ kernel/ptrace.c        |   20 ++++++++++++++++----
+ kernel/signal.c        |    2 +-
+ 3 files changed, 18 insertions(+), 5 deletions(-)
 
+diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
+index 800f113..6d9282a 100644
+--- a/include/linux/ptrace.h
++++ b/include/linux/ptrace.h
+@@ -113,6 +113,7 @@
+ #include <linux/compiler.h>		/* For unlikely.  */
+ #include <linux/sched.h>		/* For struct task_struct.  */
+ 
++extern void ptrace_signal_wake_up(struct task_struct *p, int quiescent);
+ 
+ extern long arch_ptrace(struct task_struct *child, long request,
+ 			unsigned long addr, unsigned long data);
 diff --git a/kernel/ptrace.c b/kernel/ptrace.c
-index 26ae214..0b2aba5 100644
+index 4194664..1a50090 100644
 --- a/kernel/ptrace.c
 +++ b/kernel/ptrace.c
-@@ -24,6 +24,18 @@
- #include <linux/regset.h>
+@@ -25,6 +25,18 @@
  #include <linux/hw_breakpoint.h>
+ #include <linux/cn_proc.h>
  
-+static void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
++void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
 +{
 +	unsigned int state;
 +
@@ -4587,74 +5138,106 @@ index 26ae214..0b2aba5 100644
 +		kick_process(p);
 +}
  
- /*
-  * ptrace a task: make the debugger its new parent and
-@@ -92,7 +104,7 @@ void __ptrace_unlink(struct task_struct *child)
+ static int ptrace_trapping_sleep_fn(void *flags)
+ {
+@@ -106,7 +118,7 @@ void __ptrace_unlink(struct task_struct *child)
  	 * TASK_KILLABLE sleeps.
  	 */
- 	if (child->group_stop & GROUP_STOP_PENDING || task_is_traced(child))
+ 	if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child))
 -		signal_wake_up(child, task_is_traced(child));
 +		ptrace_signal_wake_up(child, task_is_traced(child));
  
  	spin_unlock(&child->sighand->siglock);
  }
-@@ -245,7 +257,7 @@ static int ptrace_attach(struct task_struct *task)
+@@ -296,7 +308,7 @@ static int ptrace_attach(struct task_struct *task, long request,
  	 */
- 	if (task_is_stopped(task)) {
- 		task->group_stop |= GROUP_STOP_PENDING | GROUP_STOP_TRAPPING;
+ 	if (task_is_stopped(task) &&
+ 	    task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING))
 -		signal_wake_up(task, 1);
 +		ptrace_signal_wake_up(task, 1);
- 		wait_trap = true;
- 	}
  
+ 	spin_unlock(&task->sighand->siglock);
+ 
+@@ -731,7 +743,7 @@ int ptrace_request(struct task_struct *child, long request,
+ 		 * tracee into STOP.
+ 		 */
+ 		if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP)))
+-			signal_wake_up(child, child->jobctl & JOBCTL_LISTENING);
++			ptrace_signal_wake_up(child, child->jobctl & JOBCTL_LISTENING);
+ 
+ 		unlock_task_sighand(child, &flags);
+ 		ret = 0;
+@@ -760,7 +772,7 @@ int ptrace_request(struct task_struct *child, long request,
+ 			 * start of this trap and now.  Trigger re-trap.
+ 			 */
+ 			if (child->jobctl & JOBCTL_TRAP_NOTIFY)
+-				signal_wake_up(child, true);
++				ptrace_signal_wake_up(child, true);
+ 			ret = 0;
+ 		}
+ 		unlock_task_sighand(child, &flags);
+diff --git a/kernel/signal.c b/kernel/signal.c
+index 3e8e0b1..0dc6abb 100644
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -854,7 +854,7 @@ static void ptrace_trap_notify(struct task_struct *t)
+ 	assert_spin_locked(&t->sighand->siglock);
+ 
+ 	task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY);
+-	signal_wake_up(t, t->jobctl & JOBCTL_LISTENING);
++	ptrace_signal_wake_up(t, t->jobctl & JOBCTL_LISTENING);
+ }
+ 
+ /*
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:14 2011
+
+From davej  Wed Aug  3 15:15:58 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:14 -0400 (EDT)
-Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
- zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:12 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:15:58 -0400 (EDT)
+Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO
+ zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:13:17 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 72BBDA5D58;
-	Sun,  7 Aug 2011 15:18:12 -0400 (EDT)
-Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id k8I1SMuU0ydh; Sun,  7 Aug 2011 15:18:12 -0400 (EDT)
+	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 8FF88DA558;
+	Wed,  3 Aug 2011 15:12:40 -0400 (EDT)
+Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id 1cOfIyuaRoO3; Wed,  3 Aug 2011 15:12:40 -0400 (EDT)
 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 5DFAB9C7FA;
-	Sun,  7 Aug 2011 15:18:12 -0400 (EDT)
+	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 7B6E8DA4A9;
+	Wed,  3 Aug 2011 15:12:40 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JIAjF028676;
-	Sun, 7 Aug 2011 15:18:10 -0400
+	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCXpn023459;
+	Wed, 3 Aug 2011 15:12:33 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:34 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:31 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:01 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:09:59 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 06/22] wait_task_inactive: treat task->state and
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 13/31] wait_task_inactive: treat task->state and
 	match_state as bitmasks
-Message-ID: <20110807191531.GA14393 at redhat.com>
+Message-ID: <20110803190959.GA30962 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
 Status: RO
-Content-Length: 1557
-Lines: 38
+Content-Length: 1558
+Lines: 39
 
 Change wait_task_inactive() to check "state & match_state" instead of
 "state == match_state". This should not make any difference, but this
@@ -4680,10 +5263,10 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/kernel/sched.c b/kernel/sched.c
-index 3f2e502..ade7997 100644
+index ccacdbd..66ef2fb 100644
 --- a/kernel/sched.c
 +++ b/kernel/sched.c
-@@ -2277,7 +2277,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state)
+@@ -2289,7 +2289,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state)
  		 * is actually now running somewhere else!
  		 */
  		while (task_running(rq, p)) {
@@ -4695,50 +5278,51 @@ index 3f2e502..ade7997 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:15 2011
+
+From davej  Wed Aug  3 15:16:24 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:15 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:24 -0400 (EDT)
 Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
  zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:15 -0400 (EDT)
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:21 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 1FD1B1322A2;
-	Sun,  7 Aug 2011 15:18:15 -0400 (EDT)
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 34C189DC30;
+	Wed,  3 Aug 2011 15:12:43 -0400 (EDT)
 Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
 	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id gfct30463vGS; Sun,  7 Aug 2011 15:18:15 -0400 (EDT)
-Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 01C04128FDA;
-	Sun,  7 Aug 2011 15:18:15 -0400 (EDT)
+	with ESMTP id RHggq6bqo+Q9; Wed,  3 Aug 2011 15:12:43 -0400 (EDT)
+Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 210D59DC14;
+	Wed,  3 Aug 2011 15:12:43 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JICKL027777;
-	Sun, 7 Aug 2011 15:18:13 -0400
+	by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p73JCZsD022395;
+	Wed, 3 Aug 2011 15:12:36 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:36 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:34 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:03 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:01 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 07/22] introduce TASK_UTRACED state
-Message-ID: <20110807191534.GA14396 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 14/31] introduce TASK_UTRACED state
+Message-ID: <20110803191001.GA30969 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
+X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12
 Status: RO
-Content-Length: 2912
-Lines: 83
+Content-Length: 2913
+Lines: 84
 
 Introduce TASK_UTRACED state, will be used by utrace instead of TASK_TRACED.
 
@@ -4752,7 +5336,7 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  2 files changed, 17 insertions(+), 14 deletions(-)
 
 diff --git a/fs/proc/array.c b/fs/proc/array.c
-index 496fef3..bfaa998 100644
+index f0c0ea2..e0daec4 100644
 --- a/fs/proc/array.c
 +++ b/fs/proc/array.c
 @@ -138,11 +138,12 @@ static const char * const task_state_array[] = {
@@ -4774,7 +5358,7 @@ index 496fef3..bfaa998 100644
  
  static inline const char *get_task_state(struct task_struct *tsk)
 diff --git a/include/linux/sched.h b/include/linux/sched.h
-index b87de83..7a0008c 100644
+index c6d79af..f3f0a77 100644
 --- a/include/linux/sched.h
 +++ b/include/linux/sched.h
 @@ -184,16 +184,17 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
@@ -4824,50 +5408,51 @@ index b87de83..7a0008c 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:17 2011
+
+From davej  Wed Aug  3 15:16:02 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:17 -0400 (EDT)
-Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
- zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:17 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:02 -0400 (EDT)
+Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO
+ zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:13:18 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id B634FA5D5A;
-	Sun,  7 Aug 2011 15:18:17 -0400 (EDT)
-Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id 3vEyYZtZ8hD5; Sun,  7 Aug 2011 15:18:17 -0400 (EDT)
-Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 9921A9C7FA;
-	Sun,  7 Aug 2011 15:18:17 -0400 (EDT)
+	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id D7FFADA44E;
+	Wed,  3 Aug 2011 15:12:45 -0400 (EDT)
+Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id LFGdvSMswLJT; Wed,  3 Aug 2011 15:12:45 -0400 (EDT)
+Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
+	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id BA46CDA441;
+	Wed,  3 Aug 2011 15:12:45 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JIFH8028686;
-	Sun, 7 Aug 2011 15:18:16 -0400
+	by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCcpZ029424;
+	Wed, 3 Aug 2011 15:12:39 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:39 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:37 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:06 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:04 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 08/22] utrace: use TASK_UTRACED instead of TASK_TRACED
-Message-ID: <20110807191537.GA14403 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 15/31] utrace: use TASK_UTRACED instead of TASK_TRACED
+Message-ID: <20110803191004.GA30972 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
 Status: RO
-Content-Length: 4315
-Lines: 129
+Content-Length: 4316
+Lines: 130
 
 Change utrace.c to use TASK_UTRACED instead of TASK_TRACED.
 
@@ -4887,7 +5472,7 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  1 files changed, 14 insertions(+), 12 deletions(-)
 
 diff --git a/kernel/utrace.c b/kernel/utrace.c
-index d7c547c..be98607 100644
+index cebc390..2097103 100644
 --- a/kernel/utrace.c
 +++ b/kernel/utrace.c
 @@ -462,6 +462,8 @@ static void put_detached_list(struct list_head *list)
@@ -4999,59 +5584,57 @@ index d7c547c..be98607 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:19 2011
+
+From davej  Wed Aug  3 15:21:40 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:19 -0400 (EDT)
-Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO
- zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:24 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:21:40 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
+ zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:42 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 53AC0D89A9;
-	Sun,  7 Aug 2011 15:18:20 -0400 (EDT)
-Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id CGhyA84rXAKN; Sun,  7 Aug 2011 15:18:20 -0400 (EDT)
-Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
-	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 36B2CD8988;
-	Sun,  7 Aug 2011 15:18:20 -0400 (EDT)
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 7035E9DECC;
+	Wed,  3 Aug 2011 15:12:48 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id rmRalMQFlNua; Wed,  3 Aug 2011 15:12:48 -0400 (EDT)
+Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 5CC809DEC9;
+	Wed,  3 Aug 2011 15:12:48 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JIIFB028696;
-	Sun, 7 Aug 2011 15:18:18 -0400
+	by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p73JCfwv010344;
+	Wed, 3 Aug 2011 15:12:41 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:41 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:39 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:09 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:07 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 09/22] tracehooks: kill tracehook_finish_jctl(), add
-	tracehook_finish_stop()
-Message-ID: <20110807191539.GA14406 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 16/31] reintroduce tracehook_finish_jctl() as
+	utrace_end_stop()
+Message-ID: <20110803191007.GA30979 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
+X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11
 Status: RO
-Content-Length: 2781
-Lines: 85
+Content-Length: 2401
+Lines: 77
 
-tracehook_finish_jctl() is needed to avoid the races with SIGKILL
-which wakes up UTRACED task, and thus it should be called every time
-after the STOPPED/TRACED/UTRACED returns from schedule(), remember
-that TASK_UTRACED can be added while the task is STOPPED/UTRACED.
-
-- rename it to tracehook_finish_stop(),jctl no longer matches the
-  reality.
+utrace_finish_stop() is needed to avoid the races with SIGKILL which
+wakes up UTRACED task, and thus it should be called every time after
+the STOPPED/TRACED/UTRACED returns from schedule(), remember that
+TASK_UTRACED can be added while the task is STOPPED/UTRACED.
 
 - change do_signal_state() to call this helper right after schedule(),
   otherwise this logic is broken by the upstream changes
@@ -5061,62 +5644,56 @@ that TASK_UTRACED can be added while the task is STOPPED/UTRACED.
 
 Signed-off-by: Oleg Nesterov <oleg at redhat.com>
 ---
- include/linux/tracehook.h |    6 +++---
- kernel/signal.c           |    5 +++--
- kernel/utrace.c           |    2 +-
- 3 files changed, 7 insertions(+), 6 deletions(-)
+ include/linux/utrace.h |   11 +++++++++++
+ kernel/signal.c        |    5 +++++
+ kernel/utrace.c        |    2 +-
+ 3 files changed, 17 insertions(+), 1 deletions(-)
 
-diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
-index 7d7bdde..3c7b6b3 100644
---- a/include/linux/tracehook.h
-+++ b/include/linux/tracehook.h
-@@ -528,11 +528,11 @@ static inline int tracehook_get_signal(struct task_struct *task,
+diff --git a/include/linux/utrace.h b/include/linux/utrace.h
+index cf13839..0279c74 100644
+--- a/include/linux/utrace.h
++++ b/include/linux/utrace.h
+@@ -719,4 +719,15 @@ static inline void utrace_exit_notify(struct task_struct *task,
+ 		utrace_report_death(task, group_dead, signal);
  }
  
- /**
-- * tracehook_finish_jctl - report about return from job control stop
-+ * tracehook_finish_stop - report about return from STOPPED/TRACED
-  *
-- * This is called by do_signal_stop() after wakeup.
++/**
++ * utrace_end_stop - report about return from STOPPED/TRACED
++ *
 + * This is called by do_signal_stop() and ptrace_stop after wakeup.
-  */
--static inline void tracehook_finish_jctl(void)
-+static inline void tracehook_finish_stop(void)
- {
- 	if (task_utrace_flags(current))
- 		utrace_finish_stop();
++ */
++static inline void utrace_end_stop(void)
++{
++	if (task_utrace_flags(current))
++		utrace_finish_stop();
++}
++
+ #endif	/* linux/utrace.h */
 diff --git a/kernel/signal.c b/kernel/signal.c
-index 4fcf1c7..a7979ad 100644
+index 0dc6abb..a625309 100644
 --- a/kernel/signal.c
 +++ b/kernel/signal.c
-@@ -1816,6 +1816,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
+@@ -1895,6 +1895,8 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
  		read_unlock(&tasklist_lock);
  	}
  
-+	tracehook_finish_stop();
++	utrace_end_stop();
++
  	/*
  	 * While in TASK_TRACED, we were considered "frozen enough".
  	 * Now that we woke up, it's crucial if we're supposed to be
-@@ -1952,6 +1953,8 @@ retry:
+@@ -2059,6 +2061,9 @@ static bool do_signal_stop(int signr)
+ 
  		/* Now we don't run again until woken by SIGCONT or SIGKILL */
  		schedule();
- 
-+		tracehook_finish_stop();
 +
- 		spin_lock_irq(&current->sighand->siglock);
++		utrace_end_stop();
++
+ 		return true;
  	} else {
- 		ptrace_stop(current->group_stop & GROUP_STOP_SIGMASK,
-@@ -1974,8 +1977,6 @@ retry:
- 
- 	spin_unlock_irq(&current->sighand->siglock);
- 
--	tracehook_finish_jctl();
--
- 	return 1;
- }
- 
+ 		/*
 diff --git a/kernel/utrace.c b/kernel/utrace.c
-index be98607..daa96b9 100644
+index 2097103..d41b982 100644
 --- a/kernel/utrace.c
 +++ b/kernel/utrace.c
 @@ -741,7 +741,7 @@ static bool utrace_reset(struct task_struct *task, struct utrace *utrace)
@@ -5131,50 +5708,51 @@ index be98607..daa96b9 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:18 2011
+
+From davej  Wed Aug  3 15:21:41 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:18 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:21:41 -0400 (EDT)
 Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
  zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:22 -0400 (EDT)
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:42 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id DD6839C7FA;
-	Sun,  7 Aug 2011 15:18:22 -0400 (EDT)
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 153719DD18;
+	Wed,  3 Aug 2011 15:12:51 -0400 (EDT)
 Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
 	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id hZs6VyadcD7K; Sun,  7 Aug 2011 15:18:22 -0400 (EDT)
-Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id C7B129C7DE;
-	Sun,  7 Aug 2011 15:18:22 -0400 (EDT)
+	with ESMTP id ffM0oM8RRtgL; Wed,  3 Aug 2011 15:12:51 -0400 (EDT)
+Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 0253E9DEC9;
+	Wed,  3 Aug 2011 15:12:51 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p77JIKMe020605;
-	Sun, 7 Aug 2011 15:18:21 -0400
+	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCh9Z023559;
+	Wed, 3 Aug 2011 15:12:44 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:44 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:42 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:11 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:09 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 10/22] teach wake_up_quiescent() to do "selective" wake_up
-Message-ID: <20110807191542.GA14409 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 17/31] teach wake_up_quiescent() to do "selective" wake_up
+Message-ID: <20110803191009.GA30982 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
 Status: RO
-Content-Length: 1334
-Lines: 45
+Content-Length: 1335
+Lines: 46
 
 Both utrace and ptrace can want the same thread to be quiescent, in this
 case its state is TASK_TRACED | TASK_UTRACED. And this also means that
@@ -5189,10 +5767,10 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  1 files changed, 15 insertions(+), 0 deletions(-)
 
 diff --git a/kernel/signal.c b/kernel/signal.c
-index a7979ad..57552e6 100644
+index a625309..0d1675a 100644
 --- a/kernel/signal.c
 +++ b/kernel/signal.c
-@@ -651,11 +651,26 @@ void signal_wake_up(struct task_struct *t, int resume)
+@@ -701,11 +701,26 @@ void signal_wake_up(struct task_struct *t, int resume)
  		kick_process(t);
  }
  
@@ -5222,51 +5800,52 @@ index a7979ad..57552e6 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:20 2011
+
+From davej  Wed Aug  3 15:21:43 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:20 -0400 (EDT)
-Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
- zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:25 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:21:43 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
+ zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:43 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 7C2991322AA;
-	Sun,  7 Aug 2011 15:18:25 -0400 (EDT)
-Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id rHOxOwY4bOdr; Sun,  7 Aug 2011 15:18:25 -0400 (EDT)
-Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 67ABD128FDA;
-	Sun,  7 Aug 2011 15:18:25 -0400 (EDT)
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id B0E899DECF;
+	Wed,  3 Aug 2011 15:12:53 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id s0bDFhAmsQWN; Wed,  3 Aug 2011 15:12:53 -0400 (EDT)
+Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 9DC6E9DEC9;
+	Wed,  3 Aug 2011 15:12:53 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p77JINVP029911;
-	Sun, 7 Aug 2011 15:18:23 -0400
+	by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCkUr029453;
+	Wed, 3 Aug 2011 15:12:46 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:47 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:45 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:14 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:12 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 11/22] ptrace_stop: do not assume the task is running after
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 18/31] ptrace_stop: do not assume the task is running after
 	wake_up_quiescent()
-Message-ID: <20110807191545.GA14416 at redhat.com>
+Message-ID: <20110803191012.GA30985 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
 Status: RO
-Content-Length: 961
-Lines: 30
+Content-Length: 956
+Lines: 31
 
 If ptrace_stop() sets TASK_TRACED and then detects we should not stop,
 it can race with utrace_do_stop() which can see TASK_TRACED and add
@@ -5278,190 +5857,314 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  1 files changed, 8 insertions(+), 0 deletions(-)
 
 diff --git a/kernel/signal.c b/kernel/signal.c
-index 57552e6..89e691d 100644
+index 0d1675a..249760f 100644
 --- a/kernel/signal.c
 +++ b/kernel/signal.c
-@@ -1829,6 +1829,14 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
+@@ -1908,6 +1908,14 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
  		if (clear_code)
  			current->exit_code = 0;
  		read_unlock(&tasklist_lock);
 +
-+		/*
-+		 * It is possible that __TASK_UTRACED was added by utrace
-+		 * while we were __TASK_TRACED and before we take ->siglock
-+		 * for wake_up_quiescent(), we need to block in this case.
-+		 * Otherwise this is unnecessary but absolutely harmless.
-+		 */
-+		schedule();
- 	}
++		/*
++		 * It is possible that __TASK_UTRACED was added by utrace
++		 * while we were __TASK_TRACED and before we take ->siglock
++		 * for wake_up_quiescent(), we need to block in this case.
++		 * Otherwise this is unnecessary but absolutely harmless.
++		 */
++		schedule();
+ 	}
+ 
+ 	utrace_end_stop();
+-- 
+1.5.5.1
+
+
+From davej  Wed Aug  3 15:16:26 2011
+Return-Path: oleg at redhat.com
+X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
+	gelk.kernelslacker.org
+X-Spam-Level: 
+X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
+	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
+Received: from mail.corp.redhat.com [10.5.5.52]
+	by gelk with IMAP (fetchmail-6.3.20)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:26 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
+ zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:22 -0400 (EDT)
+Received: from localhost (localhost.localdomain [127.0.0.1])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 69B489DC62;
+	Wed,  3 Aug 2011 15:12:56 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id 4BNNeoYSdCTc; Wed,  3 Aug 2011 15:12:56 -0400 (EDT)
+Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 4A9899DC14;
+	Wed,  3 Aug 2011 15:12:56 -0400 (EDT)
+Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
+	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCnRf023575;
+	Wed, 3 Aug 2011 15:12:49 -0400
+Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:16 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:14 +0200
+From: Oleg Nesterov <oleg at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 19/31] get_signal_to_deliver: restore/restructure
+	utrace/ptrace signal reporting
+Message-ID: <20110803191014.GA30992 at redhat.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
+User-Agent: Mutt/1.5.18 (2008-05-17)
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
+Status: RO
+Content-Length: 3556
+Lines: 115
+
+- Reintroduce tracehook_get_signal() as utrace_hook_signal().
+
+- Change get_signal_to_deliver() to call utrace_hook_signal() first,
+  before dequeue_signal()
+
+- Always call ptrace_signal() if signal != SIGKILL, no matter whether
+  this signal comes from utrace or not.
+
+  Since this can change signr again, update "struct k_sigaction *ka"
+  in this case.
+
+IOW, roughly, ptrace acts as if it is the last attached engine, it
+takes the final decision about the signal.
+
+Signed-off-by: Oleg Nesterov <oleg at redhat.com>
+---
+ include/linux/utrace.h |   31 +++++++++++++++++++++++++++++++
+ kernel/signal.c        |   30 ++++++++++++++++++++----------
+ 2 files changed, 51 insertions(+), 10 deletions(-)
+
+diff --git a/include/linux/utrace.h b/include/linux/utrace.h
+index 0279c74..63103e2 100644
+--- a/include/linux/utrace.h
++++ b/include/linux/utrace.h
+@@ -730,4 +730,35 @@ static inline void utrace_end_stop(void)
+ 		utrace_finish_stop();
+ }
+ 
++/**
++ * utrace_hook_signal - deliver synthetic signal to traced task
++ * @task:		@current
++ * @regs:		task_pt_regs(@current)
++ * @info:		details of synthetic signal
++ * @return_ka:		sigaction for synthetic signal
++ *
++ * Return zero to check for a real pending signal normally.
++ * Return -1 after releasing the siglock to repeat the check.
++ * Return a signal number to induce an artificial signal delivery,
++ * setting *@info and *@return_ka to specify its details and behavior.
++ *
++ * The @return_ka->sa_handler value controls the disposition of the
++ * signal, no matter the signal number.  For %SIG_DFL, the return value
++ * is a representative signal to indicate the behavior (e.g. %SIGTERM
++ * for death, %SIGQUIT for core dump, %SIGSTOP for job control stop,
++ * %SIGTSTP for stop unless in an orphaned pgrp), but the signal number
++ * reported will be @info->si_signo instead.
++ *
++ * Called with @task->sighand->siglock held, before dequeuing pending signals.
++ */
++static inline int utrace_hook_signal(struct task_struct *task,
++				       struct pt_regs *regs,
++				       siginfo_t *info,
++				       struct k_sigaction *return_ka)
++{
++	if (unlikely(task_utrace_flags(task)))
++		return utrace_get_signal(task, regs, info, return_ka);
++	return 0;
++}
++
+ #endif	/* linux/utrace.h */
+diff --git a/kernel/signal.c b/kernel/signal.c
+index 249760f..3c783d3 100644
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -2234,17 +2234,27 @@ relock:
+ 	for (;;) {
+ 		struct k_sigaction *ka;
+ 
+-		if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) &&
+-		    do_signal_stop(0))
++		signr = utrace_hook_signal(current, regs, info, return_ka);
++		if (unlikely(signr < 0))
+ 			goto relock;
+ 
+-		if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) {
+-			do_jobctl_trap();
+-			spin_unlock_irq(&sighand->siglock);
+-			goto relock;
+-		}
++		if (unlikely(signr != 0))
++			ka = return_ka;
++		else {
++			if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) &&
++			    do_signal_stop(0))
++				goto relock;
+ 
+-		signr = dequeue_signal(current, &current->blocked, info);
++			if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) {
++				do_jobctl_trap();
++				spin_unlock_irq(&sighand->siglock);
++				goto relock;
++			}
++
++			signr = dequeue_signal(current, &current->blocked, info);
++
++			ka = &sighand->action[signr-1];
++		}
+ 
+ 		if (!signr)
+ 			break; /* will return 0 */
+@@ -2254,9 +2264,9 @@ relock:
+ 					      regs, cookie);
+ 			if (!signr)
+ 				continue;
+-		}
+ 
+-		ka = &sighand->action[signr-1];
++			ka = &sighand->action[signr-1];
++		}
  
- 	tracehook_finish_stop();
+ 		/* Trace actually delivered signals. */
+ 		trace_signal_deliver(signr, info, ka);
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:21 2011
+
+From davej  Wed Aug  3 15:16:27 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:21 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:27 -0400 (EDT)
 Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
  zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:28 -0400 (EDT)
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:22 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 1B4B91322AE;
-	Sun,  7 Aug 2011 15:18:28 -0400 (EDT)
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 119589DC72;
+	Wed,  3 Aug 2011 15:12:59 -0400 (EDT)
 Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
 	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id q5tv0cJeZqLD; Sun,  7 Aug 2011 15:18:28 -0400 (EDT)
+	with ESMTP id Vxp8fnt8hEcf; Wed,  3 Aug 2011 15:12:59 -0400 (EDT)
 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 071461322A9;
-	Sun,  7 Aug 2011 15:18:28 -0400 (EDT)
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id F22049DCAE;
+	Wed,  3 Aug 2011 15:12:58 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p77JIPFB020635;
-	Sun, 7 Aug 2011 15:18:26 -0400
+	by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p73JCpO4010401;
+	Wed, 3 Aug 2011 15:12:52 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:49 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:47 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:19 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:17 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 12/22] get_signal_to_deliver: restructure utrace/ptrace
-	signal reporting
-Message-ID: <20110807191547.GA14419 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 20/31] utrace_get_signal:
+	s/JOBCTL_STOP_PENDING/JOBCTL_PENDING_MASK/
+Message-ID: <20110803191017.GA30995 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
 X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11
 Status: RO
-Content-Length: 2011
-Lines: 72
+Content-Length: 1204
+Lines: 33
 
-get_signal_to_deliver() assumes that either tracehook_get_signal() does
-nothing (without CONFIG_UTRACE), or it also reports the signal to ptrace
-engine implemented on top of utrace. Now that ptrace works independently
-this doesn't work.
+utrace_get_signal() checks JOBCTL_STOP_PENDING to detect the
+case when we should not try to dequeue the signal but should
+try to participate in the group-stop.
 
-Change the code to call ptrace_signal() after tracehook_get_signal().
+With the recent changes this is not enough, everything which
+contrbutes to recalc_sigpending_tsk() should be respected.
 
-Move ->ptrace check from ptrace_signal() to get_signal_to_deliver(),
-we do not want to change *return_ka if it was initialized by utrace
-and the task is not traced.
-
-IOW, roughly, ptrace acts as if it is the last attached engine, it
-takes the final decision about the signal.
+Check JOBCTL_PENDING_MASK instead. This matches the
+JOBCTL_STOP_PENDING | JOBCTL_TRAP_MASK code in the caller,
+get_signal_to_deliver(). Note that this code won't run if
+utrace_get_signal() returns signr > 0.
 
 Signed-off-by: Oleg Nesterov <oleg at redhat.com>
 ---
- kernel/signal.c |   24 +++++++++++-------------
- 1 files changed, 11 insertions(+), 13 deletions(-)
+ kernel/utrace.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
 
-diff --git a/kernel/signal.c b/kernel/signal.c
-index 89e691d..d0e0c67 100644
---- a/kernel/signal.c
-+++ b/kernel/signal.c
-@@ -2006,9 +2006,6 @@ retry:
- static int ptrace_signal(int signr, siginfo_t *info,
- 			 struct pt_regs *regs, void *cookie)
- {
--	if (!task_ptrace(current))
--		return signr;
--
- 	ptrace_signal_deliver(regs, cookie);
- 
- 	/* Let the debugger run.  */
-@@ -2110,6 +2107,7 @@ relock:
- 		signr = tracehook_get_signal(current, regs, info, return_ka);
- 		if (unlikely(signr < 0))
- 			goto relock;
-+
- 		if (unlikely(signr != 0))
- 			ka = return_ka;
- 		else {
-@@ -2117,18 +2115,18 @@ relock:
- 				     GROUP_STOP_PENDING) && do_signal_stop(0))
- 				goto relock;
- 
--			signr = dequeue_signal(current, &current->blocked,
--					       info);
-+			signr = dequeue_signal(current, &current->blocked, info);
- 
--			if (!signr)
--				break; /* will return 0 */
-+			ka = &sighand->action[signr-1];
-+		}
- 
--			if (signr != SIGKILL) {
--				signr = ptrace_signal(signr, info,
--						      regs, cookie);
--				if (!signr)
--					continue;
--			}
-+		if (!signr)
-+			break; /* will return 0 */
-+
-+		if (signr != SIGKILL && current->ptrace) {
-+			signr = ptrace_signal(signr, info, regs, cookie);
-+			if (!signr)
-+				continue;
- 
- 			ka = &sighand->action[signr-1];
- 		}
+diff --git a/kernel/utrace.c b/kernel/utrace.c
+index d41b982..0bb0a06 100644
+--- a/kernel/utrace.c
++++ b/kernel/utrace.c
+@@ -2027,7 +2027,7 @@ int utrace_get_signal(struct task_struct *task, struct pt_regs *regs,
+ 		ka = NULL;
+ 		memset(return_ka, 0, sizeof *return_ka);
+ 	} else if (!(task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) ||
+-		   unlikely(task->jobctl & JOBCTL_STOP_PENDING)) {
++		   unlikely(task->jobctl & JOBCTL_PENDING_MASK)) {
+ 		/*
+ 		 * If no engine is interested in intercepting signals or
+ 		 * we must stop, let the caller just dequeue them normally
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:22 2011
+
+From davej  Wed Aug  3 15:16:03 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:22 -0400 (EDT)
-Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
- zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:30 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:03 -0400 (EDT)
+Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO
+ zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:13:19 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id BFD8F1322A2;
-	Sun,  7 Aug 2011 15:18:30 -0400 (EDT)
-Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id JczS8HsLYY6X; Sun,  7 Aug 2011 15:18:30 -0400 (EDT)
-Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id A8F91128FDA;
-	Sun,  7 Aug 2011 15:18:30 -0400 (EDT)
+	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id A9253DA3CB;
+	Wed,  3 Aug 2011 15:13:01 -0400 (EDT)
+Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id HLlRhTJ2MbYS; Wed,  3 Aug 2011 15:13:01 -0400 (EDT)
+Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22])
+	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 9582C4C43B;
+	Wed,  3 Aug 2011 15:13:01 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p77JIS1m029940;
-	Sun, 7 Aug 2011 15:18:29 -0400
+	by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCsFX008586;
+	Wed, 3 Aug 2011 15:12:54 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:52 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:50 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:22 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:20 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 13/22] introduce ptrace_set_syscall_trace()
-Message-ID: <20110807191550.GA14426 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 21/31] introduce ptrace_set_syscall_trace()
+Message-ID: <20110803191020.GA31002 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22
 Status: RO
-Content-Length: 1580
-Lines: 51
+Content-Length: 1549
+Lines: 52
 
 No functional changes. Add the new helper, ptrace_set_syscall_trace(),
 which should be used to set/clear TIF_SYSCALL_TRACE in ptrace code.
@@ -5473,10 +6176,10 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  1 files changed, 10 insertions(+), 5 deletions(-)
 
 diff --git a/kernel/ptrace.c b/kernel/ptrace.c
-index 0b2aba5..b6fd922 100644
+index 1a50090..dc2ad34 100644
 --- a/kernel/ptrace.c
 +++ b/kernel/ptrace.c
-@@ -37,6 +37,14 @@ static void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
+@@ -38,6 +38,14 @@ void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
  		kick_process(p);
  }
  
@@ -5488,10 +6191,10 @@ index 0b2aba5..b6fd922 100644
 +		clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
 +}
 +
- /*
-  * ptrace a task: make the debugger its new parent and
-  * move it to the ptrace list.
-@@ -364,7 +372,7 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
+ static int ptrace_trapping_sleep_fn(void *flags)
+ {
+ 	schedule();
+@@ -418,7 +426,7 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
  
  	/* Architecture-specific hardware disable .. */
  	ptrace_disable(child);
@@ -5500,7 +6203,7 @@ index 0b2aba5..b6fd922 100644
  
  	write_lock_irq(&tasklist_lock);
  	/*
-@@ -551,10 +559,7 @@ static int ptrace_resume(struct task_struct *child, long request,
+@@ -606,10 +614,7 @@ static int ptrace_resume(struct task_struct *child, long request,
  	if (!valid_signal(data))
  		return -EIO;
  
@@ -5515,50 +6218,51 @@ index 0b2aba5..b6fd922 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:23 2011
+
+From davej  Wed Aug  3 15:21:45 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:23 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:21:45 -0400 (EDT)
 Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
  zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:33 -0400 (EDT)
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:43 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 585699C7DE;
-	Sun,  7 Aug 2011 15:18:33 -0400 (EDT)
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 5C4889DEE6;
+	Wed,  3 Aug 2011 15:13:04 -0400 (EDT)
 Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
 	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id Zp+5oAzhYq2W; Sun,  7 Aug 2011 15:18:33 -0400 (EDT)
-Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 44532909E4;
-	Sun,  7 Aug 2011 15:18:33 -0400 (EDT)
+	with ESMTP id eXIPU4nVv+7Z; Wed,  3 Aug 2011 15:13:04 -0400 (EDT)
+Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 3F82C9DED6;
+	Wed,  3 Aug 2011 15:13:04 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p77JIV6n020657;
-	Sun, 7 Aug 2011 15:18:31 -0400
+	by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCueo029507;
+	Wed, 3 Aug 2011 15:12:57 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:54 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:52 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:24 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:22 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 14/22] introduce PT_SYSCALL_TRACE flag
-Message-ID: <20110807191552.GA14429 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 22/31] introduce PT_SYSCALL_TRACE flag
+Message-ID: <20110803191022.GA31005 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
 Status: RO
-Content-Length: 2235
-Lines: 72
+Content-Length: 2268
+Lines: 73
 
 Currently tracehooks assume that if the ptraced task has
 TIF_SYSCALL_TRACE set, the tracee should report the syscall.
@@ -5577,33 +6281,33 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  3 files changed, 9 insertions(+), 3 deletions(-)
 
 diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
-index 9178d5c..98d995d 100644
+index 6d9282a..c10f610 100644
 --- a/include/linux/ptrace.h
 +++ b/include/linux/ptrace.h
-@@ -90,6 +90,8 @@
+@@ -104,6 +104,8 @@
  
  #define PT_TRACE_MASK	0x000003f4
  
-+#define PT_SYSCALL_TRACE	0x00010000
++#define PT_SYSCALL_TRACE	0x00020000
 +
  /* single stepping state bits (used on ARM and PA-RISC) */
  #define PT_SINGLESTEP_BIT	31
  #define PT_SINGLESTEP		(1<<PT_SINGLESTEP_BIT)
-@@ -187,6 +189,7 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace)
- 	child->ptrace = 0;
- 	if (unlikely(ptrace) && (current->ptrace & PT_PTRACED)) {
+@@ -227,6 +229,7 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace)
+ 
+ 	if (unlikely(ptrace) && current->ptrace) {
  		child->ptrace = current->ptrace;
 +		child->ptrace &= ~PT_SYSCALL_TRACE;
  		__ptrace_link(child, current->parent);
- 	}
  
+ 		if (child->ptrace & PT_SEIZED)
 diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
-index 3c7b6b3..6ce7a37 100644
+index ec2af67..eb9fe30 100644
 --- a/include/linux/tracehook.h
 +++ b/include/linux/tracehook.h
-@@ -76,7 +76,7 @@ static inline void ptrace_report_syscall(struct pt_regs *regs)
+@@ -59,7 +59,7 @@ static inline void ptrace_report_syscall(struct pt_regs *regs)
  {
- 	int ptrace = task_ptrace(current);
+ 	int ptrace = current->ptrace;
  
 -	if (!(ptrace & PT_PTRACED))
 +	if (!(ptrace & PT_SYSCALL_TRACE))
@@ -5611,10 +6315,10 @@ index 3c7b6b3..6ce7a37 100644
  
  	ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
 diff --git a/kernel/ptrace.c b/kernel/ptrace.c
-index b6fd922..0825a01 100644
+index dc2ad34..7deb292 100644
 --- a/kernel/ptrace.c
 +++ b/kernel/ptrace.c
-@@ -39,10 +39,13 @@ static void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
+@@ -40,10 +40,13 @@ void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
  
  static void ptrace_set_syscall_trace(struct task_struct *p, bool on)
  {
@@ -5629,55 +6333,56 @@ index b6fd922..0825a01 100644
 +	}
  }
  
- /*
+ static int ptrace_trapping_sleep_fn(void *flags)
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:24 2011
+
+From davej  Wed Aug  3 15:16:05 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:24 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:05 -0400 (EDT)
 Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO
  zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:35 -0400 (EDT)
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:13:20 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id F0377D89A9;
-	Sun,  7 Aug 2011 15:18:35 -0400 (EDT)
+	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id E516ADA488;
+	Wed,  3 Aug 2011 15:13:06 -0400 (EDT)
 Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1])
 	by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id cBLqfABIHZ6h; Sun,  7 Aug 2011 15:18:35 -0400 (EDT)
-Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22])
-	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id DC799D8988;
-	Sun,  7 Aug 2011 15:18:35 -0400 (EDT)
+	with ESMTP id rP7Um8DZjclX; Wed,  3 Aug 2011 15:13:06 -0400 (EDT)
+Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
+	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id D155EDA3F8;
+	Wed,  3 Aug 2011 15:13:06 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JIXU3007727;
-	Sun, 7 Aug 2011 15:18:34 -0400
+	by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JCxfF029532;
+	Wed, 3 Aug 2011 15:13:00 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:15:57 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:55 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:27 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:25 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 15/22] utrace: don't clear TIF_SYSCALL_TRACE if it is
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 23/31] utrace: don't clear TIF_SYSCALL_TRACE if it is
 	needed by ptrace
-Message-ID: <20110807191555.GA14436 at redhat.com>
+Message-ID: <20110803191025.GA31012 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
 Status: RO
-Content-Length: 796
-Lines: 23
+Content-Length: 797
+Lines: 24
 
 TIF_SYSCALL_TRACE should be cleared only if both ptrace and utrace do
 not want it, change utrace_reset() to check PT_SYSCALL_TRACE before
@@ -5689,7 +6394,7 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  1 files changed, 1 insertions(+), 0 deletions(-)
 
 diff --git a/kernel/utrace.c b/kernel/utrace.c
-index daa96b9..a824ac3 100644
+index 0bb0a06..bebf6de 100644
 --- a/kernel/utrace.c
 +++ b/kernel/utrace.c
 @@ -697,6 +697,7 @@ static bool utrace_reset(struct task_struct *task, struct utrace *utrace)
@@ -5703,50 +6408,51 @@ index daa96b9..a824ac3 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:25 2011
+
+From davej  Wed Aug  3 15:16:08 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:25 -0400 (EDT)
-Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
- zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:38 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:08 -0400 (EDT)
+Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO
+ zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:15:29 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id A6B3C9C7DE;
-	Sun,  7 Aug 2011 15:18:38 -0400 (EDT)
-Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id ln+MaW5alQl7; Sun,  7 Aug 2011 15:18:38 -0400 (EDT)
-Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 8A6D2909E4;
-	Sun,  7 Aug 2011 15:18:38 -0400 (EDT)
+	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 80872DA4B2;
+	Wed,  3 Aug 2011 15:13:09 -0400 (EDT)
+Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id AbpC0Wk1ZhtT; Wed,  3 Aug 2011 15:13:09 -0400 (EDT)
+Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12])
+	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 6D97DDA3F8;
+	Wed,  3 Aug 2011 15:13:09 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JIaYf007737;
-	Sun, 7 Aug 2011 15:18:36 -0400
+	by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p73JD2RU022591;
+	Wed, 3 Aug 2011 15:13:02 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:16:00 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:15:58 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:30 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:28 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 16/22] introduce task_utrace_lock/task_utrace_unlock
-Message-ID: <20110807191558.GA14440 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 24/31] introduce task_utrace_lock/task_utrace_unlock
+Message-ID: <20110803191028.GA31015 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22
+X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12
 Status: RO
-Content-Length: 2189
-Lines: 80
+Content-Length: 2190
+Lines: 81
 
 - Add task_utrace_lock(task). It simply takes task->utrace->lock if
   this task was ever utraced. Otherwise it takes task_lock(), this
@@ -5763,10 +6469,10 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  2 files changed, 35 insertions(+), 0 deletions(-)
 
 diff --git a/include/linux/utrace.h b/include/linux/utrace.h
-index f251efe..5176f5f 100644
+index 63103e2..f37373b 100644
 --- a/include/linux/utrace.h
 +++ b/include/linux/utrace.h
-@@ -109,6 +109,12 @@ void utrace_signal_handler(struct task_struct *, int);
+@@ -117,6 +117,12 @@ void utrace_signal_handler(struct task_struct *, int);
  
  #ifndef CONFIG_UTRACE
  
@@ -5779,7 +6485,7 @@ index f251efe..5176f5f 100644
  /*
   * <linux/tracehook.h> uses these accessors to avoid #ifdef CONFIG_UTRACE.
   */
-@@ -131,6 +137,9 @@ static inline void task_utrace_proc_status(struct seq_file *m,
+@@ -139,6 +145,9 @@ static inline void task_utrace_proc_status(struct seq_file *m,
  
  #else  /* CONFIG_UTRACE */
  
@@ -5790,7 +6496,7 @@ index f251efe..5176f5f 100644
  {
  	return task->utrace_flags;
 diff --git a/kernel/utrace.c b/kernel/utrace.c
-index a824ac3..508c13c 100644
+index bebf6de..960dd9e 100644
 --- a/kernel/utrace.c
 +++ b/kernel/utrace.c
 @@ -79,6 +79,32 @@ static int __init utrace_init(void)
@@ -5829,51 +6535,52 @@ index a824ac3..508c13c 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:27 2011
+
+From davej  Wed Aug  3 15:21:46 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:27 -0400 (EDT)
-Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
- zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:41 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:21:46 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
+ zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:43 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 41B111322A2;
-	Sun,  7 Aug 2011 15:18:41 -0400 (EDT)
-Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id ypKNrfgt9t+i; Sun,  7 Aug 2011 15:18:41 -0400 (EDT)
-Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 2D805128FDA;
-	Sun,  7 Aug 2011 15:18:41 -0400 (EDT)
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 24B3E9DEF6;
+	Wed,  3 Aug 2011 15:13:12 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id 2jg9j3-p4bHL; Wed,  3 Aug 2011 15:13:12 -0400 (EDT)
+Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 119759DEF9;
+	Wed,  3 Aug 2011 15:13:12 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JIdnm028810;
-	Sun, 7 Aug 2011 15:18:39 -0400
+	by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p73JD485022603;
+	Wed, 3 Aug 2011 15:13:05 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:16:02 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:16:00 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:32 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:30 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 17/22] teach ptrace_set_syscall_trace() to play well with
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 25/31] teach ptrace_set_syscall_trace() to play well with
 	utrace
-Message-ID: <20110807191600.GA14443 at redhat.com>
+Message-ID: <20110803191030.GA31018 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
+X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12
 Status: RO
-Content-Length: 1512
-Lines: 48
+Content-Length: 1545
+Lines: 49
 
 1. ptrace_set_syscall_trace(true)->set_tsk_thread_flag(TIF_SYSCALL_TRACE)
    can race with utrace_control()->utrace_reset() path which can miss
@@ -5892,18 +6599,18 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  1 files changed, 5 insertions(+), 1 deletions(-)
 
 diff --git a/kernel/ptrace.c b/kernel/ptrace.c
-index 0825a01..209ea2d 100644
+index 7deb292..69850e9 100644
 --- a/kernel/ptrace.c
 +++ b/kernel/ptrace.c
-@@ -23,6 +23,7 @@
- #include <linux/uaccess.h>
+@@ -24,6 +24,7 @@
  #include <linux/regset.h>
  #include <linux/hw_breakpoint.h>
+ #include <linux/cn_proc.h>
 +#include <linux/utrace.h>
  
- static void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
+ void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
  {
-@@ -39,13 +40,16 @@ static void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
+@@ -40,13 +41,16 @@ void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
  
  static void ptrace_set_syscall_trace(struct task_struct *p, bool on)
  {
@@ -5920,54 +6627,55 @@ index 0825a01..209ea2d 100644
 +	task_utrace_unlock(p);
  }
  
- /*
+ static int ptrace_trapping_sleep_fn(void *flags)
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:27 2011
+
+From davej  Wed Aug  3 15:16:29 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:27 -0400 (EDT)
-Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
- zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:43 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:28 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
+ zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:24 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id E37B59C7DE;
-	Sun,  7 Aug 2011 15:18:43 -0400 (EDT)
-Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id NRVgSzxr7avy; Sun,  7 Aug 2011 15:18:43 -0400 (EDT)
-Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id C6D6E909E4;
-	Sun,  7 Aug 2011 15:18:43 -0400 (EDT)
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 062709DE55;
+	Wed,  3 Aug 2011 15:13:15 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id lhwVoEywGaPJ; Wed,  3 Aug 2011 15:13:14 -0400 (EDT)
+Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id E4C139DE11;
+	Wed,  3 Aug 2011 15:13:14 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JIfAM007754;
-	Sun, 7 Aug 2011 15:18:42 -0400
+	by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p73JD7Go010523;
+	Wed, 3 Aug 2011 15:13:08 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:16:05 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:16:03 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:35 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:33 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 18/22] introduce PT_SINGLE_STEP and PT_SINGLE_BLOCK
-Message-ID: <20110807191603.GA14450 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 26/31] introduce PT_SINGLE_STEP and PT_SINGLE_BLOCK
+Message-ID: <20110803191033.GA31025 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22
+X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11
 Status: RO
-Content-Length: 3724
-Lines: 107
+Content-Length: 3723
+Lines: 108
 
 Add the new internal ptrace flags, PT_SINGLE_STEP and PT_SINGLE_BLOCK.
 
@@ -5987,10 +6695,10 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  4 files changed, 13 insertions(+), 3 deletions(-)
 
 diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
-index 807c2a2..7ab475f 100644
+index 8252879..d1557dc 100644
 --- a/arch/x86/kernel/ptrace.c
 +++ b/arch/x86/kernel/ptrace.c
-@@ -807,6 +807,7 @@ static int ioperm_get(struct task_struct *target,
+@@ -808,6 +808,7 @@ static int ioperm_get(struct task_struct *target,
   */
  void ptrace_disable(struct task_struct *child)
  {
@@ -5999,33 +6707,33 @@ index 807c2a2..7ab475f 100644
  #ifdef TIF_SYSCALL_EMU
  	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
 diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
-index 98d995d..65b1e4f 100644
+index c10f610..2743315 100644
 --- a/include/linux/ptrace.h
 +++ b/include/linux/ptrace.h
-@@ -91,6 +91,8 @@
+@@ -105,6 +105,8 @@
  #define PT_TRACE_MASK	0x000003f4
  
- #define PT_SYSCALL_TRACE	0x00010000
-+#define PT_SINGLE_STEP		0x00020000
-+#define PT_SINGLE_BLOCK		0x00040000
+ #define PT_SYSCALL_TRACE	0x00020000
++#define PT_SINGLE_STEP		0x00040000
++#define PT_SINGLE_BLOCK		0x00080000
  
  /* single stepping state bits (used on ARM and PA-RISC) */
  #define PT_SINGLESTEP_BIT	31
-@@ -189,7 +191,8 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace)
- 	child->ptrace = 0;
- 	if (unlikely(ptrace) && (current->ptrace & PT_PTRACED)) {
+@@ -229,7 +231,8 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace)
+ 
+ 	if (unlikely(ptrace) && current->ptrace) {
  		child->ptrace = current->ptrace;
 -		child->ptrace &= ~PT_SYSCALL_TRACE;
 +		child->ptrace &=
 +			~(PT_SYSCALL_TRACE | PT_SINGLE_STEP | PT_SINGLE_BLOCK);
  		__ptrace_link(child, current->parent);
- 	}
  
+ 		if (child->ptrace & PT_SEIZED)
 diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
-index 6ce7a37..06edb52 100644
+index eb9fe30..21c8ca2 100644
 --- a/include/linux/tracehook.h
 +++ b/include/linux/tracehook.h
-@@ -121,6 +121,9 @@ static inline __must_check int tracehook_report_syscall_entry(
+@@ -104,6 +104,9 @@ static inline __must_check int tracehook_report_syscall_entry(
  	return 0;
  }
  
@@ -6035,7 +6743,7 @@ index 6ce7a37..06edb52 100644
  /**
   * tracehook_report_syscall_exit - task has just finished a system call
   * @regs:		user register state of current task
-@@ -143,7 +146,7 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
+@@ -126,7 +129,7 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
  	if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT))
  		utrace_report_syscall_exit(regs);
  
@@ -6044,7 +6752,7 @@ index 6ce7a37..06edb52 100644
  		siginfo_t info;
  		user_single_step_siginfo(current, regs, &info);
  		force_sig_info(SIGTRAP, &info, current);
-@@ -436,7 +439,7 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
+@@ -157,7 +160,7 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
  {
  	if (task_utrace_flags(current))
  		utrace_signal_handler(current, stepping);
@@ -6054,10 +6762,10 @@ index 6ce7a37..06edb52 100644
  }
  
 diff --git a/kernel/ptrace.c b/kernel/ptrace.c
-index 209ea2d..44908d0 100644
+index 69850e9..d250a71 100644
 --- a/kernel/ptrace.c
 +++ b/kernel/ptrace.c
-@@ -575,13 +575,16 @@ static int ptrace_resume(struct task_struct *child, long request,
+@@ -630,13 +630,16 @@ static int ptrace_resume(struct task_struct *child, long request,
  		clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
  #endif
  
@@ -6077,51 +6785,52 @@ index 209ea2d..44908d0 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:29 2011
+
+From davej  Wed Aug  3 15:16:30 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:29 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:30 -0400 (EDT)
 Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
  zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:46 -0400 (EDT)
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:25 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 810E31322A2;
-	Sun,  7 Aug 2011 15:18:46 -0400 (EDT)
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id B3BF49DE11;
+	Wed,  3 Aug 2011 15:13:17 -0400 (EDT)
 Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
 	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id ptiIThWTq2a6; Sun,  7 Aug 2011 15:18:46 -0400 (EDT)
-Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22])
-	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 6B665128FDA;
-	Sun,  7 Aug 2011 15:18:46 -0400 (EDT)
+	with ESMTP id zC72ecV9Jz07; Wed,  3 Aug 2011 15:13:17 -0400 (EDT)
+Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 98ACE9DE59;
+	Wed,  3 Aug 2011 15:13:17 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JIiI8007757;
-	Sun, 7 Aug 2011 15:18:44 -0400
+	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JDATh023726;
+	Wed, 3 Aug 2011 15:13:10 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:16:08 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:16:06 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:38 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:36 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 19/22] utrace: finish_resume_report: don't do
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 27/31] utrace: finish_resume_report: don't do
 	user_xxx_step() if ptrace_wants_step()
-Message-ID: <20110807191606.GA14453 at redhat.com>
+Message-ID: <20110803191036.GA31028 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
 Status: RO
-Content-Length: 2740
-Lines: 83
+Content-Length: 2741
+Lines: 84
 
 finish_resume_report() should not enable/disable the stepping if
 ptrace_wants_step() == T. If ptrace wants block_step while utrace
@@ -6138,10 +6847,10 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  2 files changed, 10 insertions(+), 7 deletions(-)
 
 diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
-index 06edb52..5612d2d 100644
+index 21c8ca2..b6812d4 100644
 --- a/include/linux/tracehook.h
 +++ b/include/linux/tracehook.h
-@@ -121,8 +121,8 @@ static inline __must_check int tracehook_report_syscall_entry(
+@@ -104,8 +104,8 @@ static inline __must_check int tracehook_report_syscall_entry(
  	return 0;
  }
  
@@ -6152,7 +6861,7 @@ index 06edb52..5612d2d 100644
  
  /**
   * tracehook_report_syscall_exit - task has just finished a system call
-@@ -146,7 +146,7 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
+@@ -129,7 +129,7 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
  	if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT))
  		utrace_report_syscall_exit(regs);
  
@@ -6161,7 +6870,7 @@ index 06edb52..5612d2d 100644
  		siginfo_t info;
  		user_single_step_siginfo(current, regs, &info);
  		force_sig_info(SIGTRAP, &info, current);
-@@ -439,7 +439,7 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
+@@ -160,7 +160,7 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
  {
  	if (task_utrace_flags(current))
  		utrace_signal_handler(current, stepping);
@@ -6171,10 +6880,10 @@ index 06edb52..5612d2d 100644
  }
  
 diff --git a/kernel/utrace.c b/kernel/utrace.c
-index 508c13c..fbabb81 100644
+index 960dd9e..05e8532 100644
 --- a/kernel/utrace.c
 +++ b/kernel/utrace.c
-@@ -1828,7 +1828,8 @@ static void finish_resume_report(struct task_struct *task,
+@@ -1829,7 +1829,8 @@ static void finish_resume_report(struct task_struct *task,
  
  	case UTRACE_BLOCKSTEP:
  		if (likely(arch_has_block_step())) {
@@ -6184,7 +6893,7 @@ index 508c13c..fbabb81 100644
  			break;
  		}
  
-@@ -1841,7 +1842,8 @@ static void finish_resume_report(struct task_struct *task,
+@@ -1842,7 +1843,8 @@ static void finish_resume_report(struct task_struct *task,
  
  	case UTRACE_SINGLESTEP:
  		if (likely(arch_has_single_step())) {
@@ -6194,7 +6903,7 @@ index 508c13c..fbabb81 100644
  		} else {
  			/*
  			 * This means some callback is to blame for failing
-@@ -1856,7 +1858,8 @@ static void finish_resume_report(struct task_struct *task,
+@@ -1857,7 +1859,8 @@ static void finish_resume_report(struct task_struct *task,
  	case UTRACE_REPORT:
  	case UTRACE_RESUME:
  	default:
@@ -6207,50 +6916,51 @@ index 508c13c..fbabb81 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:30 2011
+
+From davej  Wed Aug  3 15:16:32 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:30 -0400 (EDT)
-Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
- zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:49 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:32 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
+ zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:25 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 1C4A79C7DE;
-	Sun,  7 Aug 2011 15:18:49 -0400 (EDT)
-Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id GxHOzMqYQY8N; Sun,  7 Aug 2011 15:18:49 -0400 (EDT)
-Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 066D2909E4;
-	Sun,  7 Aug 2011 15:18:49 -0400 (EDT)
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 614CD9DE73;
+	Wed,  3 Aug 2011 15:13:20 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id jcWOXzUaaIYu; Wed,  3 Aug 2011 15:13:20 -0400 (EDT)
+Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 438889DE59;
+	Wed,  3 Aug 2011 15:13:20 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p77JIkkD030034;
-	Sun, 7 Aug 2011 15:18:47 -0400
+	by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JDDZ7029595;
+	Wed, 3 Aug 2011 15:13:13 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:16:10 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:16:08 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:40 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:38 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 20/22] ptrace: shift user_*_step() from ptrace_resume() to
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 28/31] ptrace: shift user_*_step() from ptrace_resume() to
 	ptrace_stop()
-Message-ID: <20110807191608.GA14460 at redhat.com>
+Message-ID: <20110803191038.GA31035 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
 Status: RO
-Content-Length: 2384
+Content-Length: 2374
 Lines: 70
 
 1. ptrace_resume() plays with the stopped task which can be also
@@ -6276,14 +6986,14 @@ Lines: 70
 Signed-off-by: Oleg Nesterov <oleg at redhat.com>
 ---
  kernel/ptrace.c |    4 ----
- kernel/signal.c |   12 ++++++++++++
- 2 files changed, 12 insertions(+), 4 deletions(-)
+ kernel/signal.c |   11 +++++++++++
+ 2 files changed, 11 insertions(+), 4 deletions(-)
 
 diff --git a/kernel/ptrace.c b/kernel/ptrace.c
-index 44908d0..d37b30d 100644
+index d250a71..d1ef124 100644
 --- a/kernel/ptrace.c
 +++ b/kernel/ptrace.c
-@@ -580,14 +580,10 @@ static int ptrace_resume(struct task_struct *child, long request,
+@@ -635,14 +635,10 @@ static int ptrace_resume(struct task_struct *child, long request,
  		if (unlikely(!arch_has_block_step()))
  			return -EIO;
  		child->ptrace |= PT_SINGLE_BLOCK;
@@ -6299,14 +7009,13 @@ index 44908d0..d37b30d 100644
  
  	child->exit_code = data;
 diff --git a/kernel/signal.c b/kernel/signal.c
-index d0e0c67..bc40bd7 100644
+index 3c783d3..43a3e77 100644
 --- a/kernel/signal.c
 +++ b/kernel/signal.c
-@@ -1840,6 +1840,18 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
- 	}
+@@ -1920,6 +1920,17 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
+ 
+ 	utrace_end_stop();
  
- 	tracehook_finish_stop();
-+
 +	if (current->ptrace & PT_SINGLE_BLOCK)
 +		user_enable_block_step(current);
 +	else if (current->ptrace & PT_SINGLE_STEP)
@@ -6324,50 +7033,51 @@ index d0e0c67..bc40bd7 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:31 2011
+
+From davej  Wed Aug  3 15:16:34 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:31 -0400 (EDT)
-Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO
- zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:51 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:16:34 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
+ zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:25 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id AD8D0D89A9;
-	Sun,  7 Aug 2011 15:18:51 -0400 (EDT)
-Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id LHAT6DyOymTI; Sun,  7 Aug 2011 15:18:51 -0400 (EDT)
-Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12])
-	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 99798D8988;
-	Sun,  7 Aug 2011 15:18:51 -0400 (EDT)
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 1A6019DE59;
+	Wed,  3 Aug 2011 15:13:23 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id db2hhAqFwsPu; Wed,  3 Aug 2011 15:13:23 -0400 (EDT)
+Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 034739DE83;
+	Wed,  3 Aug 2011 15:13:23 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p77JIn3U030041;
-	Sun, 7 Aug 2011 15:18:50 -0400
+	by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JDFNp008715;
+	Wed, 3 Aug 2011 15:13:16 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:16:13 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:16:11 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:43 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:41 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 21/22] ptrace_disable: no need to disable stepping
-Message-ID: <20110807191611.GA14463 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 29/31] ptrace_disable: no need to disable stepping
+Message-ID: <20110803191041.GA31039 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12
+X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22
 Status: RO
-Content-Length: 944
-Lines: 28
+Content-Length: 945
+Lines: 29
 
 ptrace_disable() is called when the tracee is quiescent and we
 are going to untrace. This means we are going to clear ->ptrace
@@ -6383,10 +7093,10 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  1 files changed, 0 insertions(+), 2 deletions(-)
 
 diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
-index 7ab475f..f1cdc7d 100644
+index d1557dc..96d315a 100644
 --- a/arch/x86/kernel/ptrace.c
 +++ b/arch/x86/kernel/ptrace.c
-@@ -807,8 +807,6 @@ static int ioperm_get(struct task_struct *target,
+@@ -808,8 +808,6 @@ static int ioperm_get(struct task_struct *target,
   */
  void ptrace_disable(struct task_struct *child)
  {
@@ -6398,50 +7108,51 @@ index 7ab475f..f1cdc7d 100644
 -- 
 1.5.5.1
 
-From davej  Sun Aug  7 15:19:32 2011
+
+From davej  Wed Aug  3 15:21:48 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Sun, 07 Aug 2011 15:19:32 -0400 (EDT)
-Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO
- zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by
- mail04.corp.redhat.com with LMTP; Sun, 7 Aug 2011 15:18:54 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:21:48 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
+ zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:52 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 57405D89A9;
-	Sun,  7 Aug 2011 15:18:54 -0400 (EDT)
-Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1])
-	by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id XgEdPuPz9LNX; Sun,  7 Aug 2011 15:18:54 -0400 (EDT)
-Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
-	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 42E6BD8988;
-	Sun,  7 Aug 2011 15:18:54 -0400 (EDT)
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 95706917AF;
+	Wed,  3 Aug 2011 15:13:25 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id ctq4DF3wXncJ; Wed,  3 Aug 2011 15:13:25 -0400 (EDT)
+Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 7FD14914AF;
+	Wed,  3 Aug 2011 15:13:25 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p77JIqEO027919;
-	Sun, 7 Aug 2011 15:18:52 -0400
+	by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p73JDIRO010579;
+	Wed, 3 Aug 2011 15:13:18 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Sun,  7 Aug 2011 21:16:15 +0200 (CEST)
-Date: Sun, 7 Aug 2011 21:16:13 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:46 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:44 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org
-Subject: [PATCH 22/22] ptrace_report_syscall: check TIF_SYSCALL_EMU
-Message-ID: <20110807191613.GA14470 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 30/31] ptrace_report_syscall: check TIF_SYSCALL_EMU
+Message-ID: <20110803191044.GA31046 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
-X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
+X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11
 Status: RO
-Content-Length: 862
-Lines: 27
+Content-Length: 858
+Lines: 28
 
 4d16a64 "introduce PT_SYSCALL_TRACE flag" breaks PTRACE_SYSEMU
 which doesn't set PT_SYSCALL_TRACE.
@@ -6456,12 +7167,12 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
-index 5612d2d..ac833de 100644
+index b6812d4..90ca578 100644
 --- a/include/linux/tracehook.h
 +++ b/include/linux/tracehook.h
-@@ -76,7 +76,7 @@ static inline void ptrace_report_syscall(struct pt_regs *regs)
+@@ -59,7 +59,7 @@ static inline void ptrace_report_syscall(struct pt_regs *regs)
  {
- 	int ptrace = task_ptrace(current);
+ 	int ptrace = current->ptrace;
  
 -	if (!(ptrace & PT_SYSCALL_TRACE))
 +	if (!(ptrace & PT_SYSCALL_TRACE) && !test_thread_flag(TIF_SYSCALL_EMU))
@@ -6471,51 +7182,125 @@ index 5612d2d..ac833de 100644
 -- 
 1.5.5.1
 
-From davej  Tue Aug  9 13:34:35 2011
+
+From davej  Wed Aug  3 15:21:49 2011
 Return-Path: oleg at redhat.com
 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
 	gelk.kernelslacker.org
 X-Spam-Level: 
 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
 	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
-Received: from mail.corp.redhat.com [10.5.5.51]
+Received: from mail.corp.redhat.com [10.5.5.52]
 	by gelk with IMAP (fetchmail-6.3.20)
-	for <davej at localhost> (single-drop); Tue, 09 Aug 2011 13:34:35 -0400 (EDT)
+	for <davej at localhost> (single-drop); Wed, 03 Aug 2011 15:21:49 -0400 (EDT)
 Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
  zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
- mail04.corp.redhat.com with LMTP; Tue, 9 Aug 2011 13:33:16 -0400 (EDT)
+ mail04.corp.redhat.com with LMTP; Wed, 3 Aug 2011 15:16:52 -0400 (EDT)
 Received: from localhost (localhost.localdomain [127.0.0.1])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 16B6E9EBAD;
-	Tue,  9 Aug 2011 13:33:16 -0400 (EDT)
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 400F49191F;
+	Wed,  3 Aug 2011 15:13:28 -0400 (EDT)
 Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
 	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
-	with ESMTP id T2mXXk1FjIIy; Tue,  9 Aug 2011 13:33:16 -0400 (EDT)
+	with ESMTP id UeLOLM29JRc7; Wed,  3 Aug 2011 15:13:28 -0400 (EDT)
 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25])
-	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 025259EBA5;
-	Tue,  9 Aug 2011 13:33:16 -0400 (EDT)
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 2D05C903F6;
+	Wed,  3 Aug 2011 15:13:28 -0400 (EDT)
 Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
-	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p79HXDVF004054;
-	Tue, 9 Aug 2011 13:33:13 -0400
+	by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p73JDKCA023784;
+	Wed, 3 Aug 2011 15:13:21 -0400
 Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
-	oleg at redhat.com; Tue,  9 Aug 2011 19:30:35 +0200 (CEST)
-Date: Tue, 9 Aug 2011 19:30:33 +0200
+	oleg at redhat.com; Wed,  3 Aug 2011 21:10:48 +0200 (CEST)
+Date: Wed, 3 Aug 2011 21:10:46 +0200
 From: Oleg Nesterov <oleg at redhat.com>
-To: "Frank Ch. Eigler" <fche at redhat.com>, Kyle McMartin <kmcmartin at redhat.com>,
-        Dave Jones <davej at redhat.com>, Josh Stone <jistone at redhat.com>,
-        Matthew Garrett <mjg at redhat.com>, David Smith <dsmith at redhat.com>
-Cc: kernel at lists.fedoraproject.org, Tony Breeds <tony at bakeyournoodle.com>
-Subject: [PATCH utrace-3.0 23/22] ptrace_report_syscall: check if
-	TIF_SYSCALL_EMU is defined
-Message-ID: <20110809173033.GA26443 at redhat.com>
-References: <20110701002053.GA25767 at redhat.com> <20110807191434.GA13184 at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH 31/31] utrace_resume: check irqs_disabled() to shut up
+	lockdep
+Message-ID: <20110803191046.GA31049 at redhat.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
-In-Reply-To: <20110807191434.GA13184 at redhat.com>
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
 User-Agent: Mutt/1.5.18 (2008-05-17)
 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25
 Status: RO
-Content-Length: 844
+Content-Length: 823
+Lines: 26
+
+utrace_resume() enables irqs unconditionally. With the recent changes
+in lockdep.c this triggers the warning. Check irqs_disabled() before
+local_irq_enable().
+
+Signed-off-by: Oleg Nesterov <oleg at redhat.com>
+---
+ kernel/utrace.c |    3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/kernel/utrace.c b/kernel/utrace.c
+index 05e8532..c817a46 100644
+--- a/kernel/utrace.c
++++ b/kernel/utrace.c
+@@ -1881,7 +1881,8 @@ void utrace_resume(struct task_struct *task, struct pt_regs *regs)
+ 	 * code path leads to calling into get_signal_to_deliver(), which
+ 	 * implicitly reenables them by virtue of spin_unlock_irq.
+ 	 */
+-	local_irq_enable();
++	if (irqs_disabled())	/* make trace_hardirqs_on() happy */
++		local_irq_enable();
+ 
+ 	/*
+ 	 * If this flag is still set it's because there was a signal
+-- 
+1.5.5.1
+
+
+From davej  Tue Aug  9 13:39:54 2011
+Return-Path: oleg at redhat.com
+X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
+	gelk.kernelslacker.org
+X-Spam-Level: 
+X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
+	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
+Received: from mail.corp.redhat.com [10.5.5.51]
+	by gelk with IMAP (fetchmail-6.3.20)
+	for <davej at localhost> (single-drop); Tue, 09 Aug 2011 13:39:54 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO
+ zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by
+ mail04.corp.redhat.com with LMTP; Tue, 9 Aug 2011 13:39:44 -0400 (EDT)
+Received: from localhost (localhost.localdomain [127.0.0.1])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 5FCAC12983C;
+	Tue,  9 Aug 2011 13:39:44 -0400 (EDT)
+Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id nDWbqog6fbHK; Tue,  9 Aug 2011 13:39:44 -0400 (EDT)
+Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11])
+	by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 4BEF712983B;
+	Tue,  9 Aug 2011 13:39:44 -0400 (EDT)
+Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
+	by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p79HdahY022801;
+	Tue, 9 Aug 2011 13:39:37 -0400
+Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
+	oleg at redhat.com; Tue,  9 Aug 2011 19:36:58 +0200 (CEST)
+Date: Tue, 9 Aug 2011 19:36:56 +0200
+From: Oleg Nesterov <oleg at redhat.com>
+To: Dave Jones <davej at redhat.com>, "Frank Ch. Eigler" <fche at redhat.com>,
+        Josh Boyer <jwboyer at redhat.com>, Josh Stone <jistone at redhat.com>,
+        Kyle McMartin <kmcmartin at redhat.com>
+Cc: kernel at lists.fedoraproject.org, utrace-devel at redhat.com
+Subject: [PATCH utrace-3.1 32/31] ptrace_report_syscall: check if
+	TIF_SYSCALL_EMU is defined
+Message-ID: <20110809173656.GC26443 at redhat.com>
+References: <20110802174514.GA23073 at redhat.com> <20110803190806.GA30619 at redhat.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <20110803190806.GA30619 at redhat.com>
+User-Agent: Mutt/1.5.18 (2008-05-17)
+X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11
+Status: RO
+Content-Length: 839
 Lines: 31
 
 From: Tony Breeds <tony at bakeyournoodle.com>
@@ -6528,12 +7313,12 @@ Signed-off-by: Oleg Nesterov <oleg at redhat.com>
  1 files changed, 6 insertions(+), 2 deletions(-)
 
 diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
-index ac833de..d5baf86 100644
+index 90ca578..a1bac95 100644
 --- a/include/linux/tracehook.h
 +++ b/include/linux/tracehook.h
-@@ -76,8 +76,12 @@ static inline void ptrace_report_syscall(struct pt_regs *regs)
+@@ -59,8 +59,12 @@ static inline void ptrace_report_syscall(struct pt_regs *regs)
  {
- 	int ptrace = task_ptrace(current);
+ 	int ptrace = current->ptrace;
  
 -	if (!(ptrace & PT_SYSCALL_TRACE) && !test_thread_flag(TIF_SYSCALL_EMU))
 -		return;
@@ -6550,3 +7335,74 @@ index ac833de..d5baf86 100644
 1.5.5.1
 
 
+From davej  Thu Sep  1 14:14:49 2011
+Return-Path: oleg at redhat.com
+X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on
+	gelk.kernelslacker.org
+X-Spam-Level: 
+X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD,
+	UNPARSEABLE_RELAY autolearn=ham version=3.3.2
+Received: from mail.corp.redhat.com [10.5.5.52]
+	by gelk with IMAP (fetchmail-6.3.20)
+	for <davej at localhost> (single-drop); Thu, 01 Sep 2011 14:14:49 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
+ zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by
+ mail04.corp.redhat.com with LMTP; Thu, 1 Sep 2011 14:13:55 -0400 (EDT)
+Received: from localhost (localhost.localdomain [127.0.0.1])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 1BA199C63F;
+	Thu,  1 Sep 2011 14:13:55 -0400 (EDT)
+Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1])
+	by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
+	with ESMTP id 0vQx9zlcQB36; Thu,  1 Sep 2011 14:13:55 -0400 (EDT)
+Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12])
+	by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 009959C63D;
+	Thu,  1 Sep 2011 14:13:55 -0400 (EDT)
+Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232])
+	by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p81IDrDX015389;
+	Thu, 1 Sep 2011 14:13:54 -0400
+Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500
+	oleg at redhat.com; Thu,  1 Sep 2011 20:10:54 +0200 (CEST)
+Date: Thu, 1 Sep 2011 20:10:53 +0200
+From: Oleg Nesterov <oleg at redhat.com>
+To: Dave Jones <davej at redhat.com>
+Cc: kernel at lists.fedoraproject.org, cebbert at redhat.com
+Subject: [PATCH F-16] bz735118: utrace: s390: fix the compile problem with
+	traps.c
+Message-ID: <20110901181053.GA24990 at redhat.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+User-Agent: Mutt/1.5.18 (2008-05-17)
+X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12
+Status: RO
+Content-Length: 777
+Lines: 27
+
+https://bugzilla.redhat.com/show_bug.cgi?id=735118
+
+d99e60e5 "tracehooks: reintroduce tracehook_consider_fatal_signal()"
+breaks the compilation of arch/s390/kernel/traps.c. Restore the
+necessary include removed by upstream 73b7d40f commit.
+
+Signed-off-by: Oleg Nesterov <oleg at redhat.com>
+---
+ arch/s390/kernel/traps.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
+index 1018ab6..50e975d 100644
+--- a/arch/s390/kernel/traps.c
++++ b/arch/s390/kernel/traps.c
+@@ -18,7 +18,7 @@
+ #include <linux/kernel.h>
+ #include <linux/string.h>
+ #include <linux/errno.h>
+-#include <linux/ptrace.h>
++#include <linux/tracehook.h>
+ #include <linux/timer.h>
+ #include <linux/mm.h>
+ #include <linux/smp.h>
+-- 
+1.5.5.1
+
+
diff --git a/xfs-Fix-possible-memory-corruption-in-xfs_readlink.patch b/xfs-Fix-possible-memory-corruption-in-xfs_readlink.patch
index 319f80d..9e810db 100644
--- a/xfs-Fix-possible-memory-corruption-in-xfs_readlink.patch
+++ b/xfs-Fix-possible-memory-corruption-in-xfs_readlink.patch
@@ -1,7 +1,40 @@
-From cbee73333a2d05c274240dff5de1b4bb74bfb497 Mon Sep 17 00:00:00 2001
+X-Spam-Checker-Version: SpamAssassin 3.4.0-r929098 (2010-03-30) on oss.sgi.com
+X-Spam-Level: 
+X-Spam-Status: No, score=-1.8 required=5.0 tests=BAYES_00,J_CHICKENPOX_64
+	autolearn=no version=3.4.0-r929098
+Received: from cuda.sgi.com (cuda1.sgi.com [192.48.157.11])
+	by oss.sgi.com (8.14.3/8.14.3/SuSE Linux 0.8) with ESMTP id p9I1KBVD036341
+	for <xfs at oss.sgi.com>; Mon, 17 Oct 2011 20:20:11 -0500
+X-ASG-Debug-ID: 1318901280-3911029d0000-NocioJ
+X-Barracuda-URL: http://cuda.sgi.com:80/cgi-bin/mark.cgi
+Received: from hades.usersys.redhat.com (localhost [127.0.0.1])
+	by cuda.sgi.com (Spam Firewall) with ESMTP id B9D1DF75F0A
+	for <xfs at oss.sgi.com>; Mon, 17 Oct 2011 18:28:01 -0700 (PDT)
+Received: from hades.usersys.redhat.com ([187.60.101.4]) by cuda.sgi.com with ESMTP id 81CuyNdYBqrtvtnD for <xfs at oss.sgi.com>; Mon, 17 Oct 2011 18:28:01 -0700 (PDT)
+Received: by hades.usersys.redhat.com (Postfix, from userid 500)
+	id 5B763E089B; Tue, 18 Oct 2011 02:18:59 -0200 (BRST)
 From: Carlos Maiolino <cmaiolino at redhat.com>
-Date: Tue, 18 Oct 2011 02:18:58 -0200
+To: xfs at oss.sgi.com
+Cc: Carlos Maiolino <cmaiolino at redhat.com>
+X-ASG-Orig-Subj: [PATCH] Fix possible memory corruption in xfs_readlink
 Subject: [PATCH] Fix possible memory corruption in xfs_readlink
+Date: Tue, 18 Oct 2011 02:18:58 -0200
+Message-Id: <1318911538-9174-1-git-send-email-cmaiolino at redhat.com>
+X-Mailer: git-send-email 1.7.6.2
+X-Barracuda-Connect: UNKNOWN[187.60.101.4]
+X-Barracuda-Start-Time: 1318901282
+X-Barracuda-Bayes: INNOCENT GLOBAL 0.0000 1.0000 -2.0210
+X-Barracuda-Virus-Scanned: by cuda.sgi.com at sgi.com
+X-Barracuda-Spam-Score: -1.42
+X-Barracuda-Spam-Status: No, SCORE=-1.42 using per-user scores of TAG_LEVEL=2.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=2.1 tests=BSF_SC5_MJ1963, RDNS_NONE
+X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.2.77645
+	Rule breakdown below
+	 pts rule name              description
+	---- ---------------------- --------------------------------------------------
+	0.10 RDNS_NONE              Delivered to trusted network by a host with no rDNS
+	0.50 BSF_SC5_MJ1963         Custom Rule MJ1963
+X-Virus-Scanned: ClamAV version 0.94.2, clamav-milter version 0.94.2 on oss.sgi.com
+X-Virus-Status: Clean
 
 Fixes a possible memory corruption when the link is larger than
 MAXPATHLEN and XFS_DEBUG is not enabled. This also remove the
@@ -10,18 +43,18 @@ xfs_readlink_by_handle() and via VFS.
 
 Signed-off-by: Carlos Maiolino <cmaiolino at redhat.com>
 ---
- fs/xfs/xfs_vnodeops.c |   10 +++++++---
- 1 files changed, 7 insertions(+), 3 deletions(-)
+ fs/xfs/xfs_vnodeops.c |   11 ++++++++---
+ 1 files changed, 8 insertions(+), 3 deletions(-)
 
 diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
-index 6197207..111870b 100644
+index 51fc429..c3288be 100644
 --- a/fs/xfs/xfs_vnodeops.c
 +++ b/fs/xfs/xfs_vnodeops.c
-@@ -545,13 +545,17 @@ xfs_readlink(
+@@ -123,13 +123,18 @@ xfs_readlink(
  
  	xfs_ilock(ip, XFS_ILOCK_SHARED);
  
--	ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK);
+-	ASSERT(S_ISLNK(ip->i_d.di_mode));
 -	ASSERT(ip->i_d.di_size <= MAXPATHLEN);
 -
  	pathlen = ip->i_d.di_size;
@@ -35,9 +68,10 @@ index 6197207..111870b 100644
 +		return XFS_ERROR(EFSCORRUPTED);
 +	}
 +
++
  	if (ip->i_df.if_flags & XFS_IFINLINE) {
  		memcpy(link, ip->i_df.if_u1.if_data, pathlen);
  		link[pathlen] = '\0';
 -- 
-1.7.6.4
+1.7.6.2
 


More information about the scm-commits mailing list